question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Does not yet support Next.js Version 13

See original GitHub issue

I’ve noticed that next-mdx-remote doesn’t work with Next.js 13.

To reproduce the issue, I tried running the official example with-mdx-remote using Next.js 13 and it doesn’t work. Trying to load the example post, I get the following error:

CleanShot 2022-10-26 at 18 41 15@2x

How to reproduce

In my own project, I’m getting a similar error relating to imports of components, so I assume the issue might be related to changes in Next.js’ bundler or build system.

I don’t get the error if I run the tests in this repo (hashicorp/next-mdx-remote) with Next.js 13. For me that’s another hint that the error might be related to bundling, since in this repo the test doesn’t import next-mdx-remote through node_modules (see https://github.com/hashicorp/next-mdx-remote/blob/f5b0e74529908efd78b981bae7121847ed751b58/__tests__/fixtures/basic/pages/index.jsx#L5-L6)

Compiled Output

Here is the compiled output of node_modules/next-mdx-remote/index.js:

import React, { useState, useEffect, useMemo } from 'react';
import { jsxRuntime } from './jsx-runtime.cjs';
import * as mdx from '@mdx-js/react';

if (typeof window !== 'undefined') {
  window.requestIdleCallback =
    window.requestIdleCallback ||
    function (cb) {
      var start = Date.now();
      return setTimeout(function () {
        cb({
          didTimeout: false,
          timeRemaining: function () {
            return Math.max(0, 50 - (Date.now() - start))
          },
        });
      }, 1)
    };

  window.cancelIdleCallback =
    window.cancelIdleCallback ||
    function (id) {
      clearTimeout(id);
    };
}

/**
 * Renders compiled source from next-mdx-remote/serialize.
 */
function MDXRemote({ compiledSource, frontmatter, scope, components = {}, lazy, }) {
    const [isReadyToRender, setIsReadyToRender] = useState(!lazy || typeof window === 'undefined');
    // if we're on the client side and `lazy` is set to true, we hydrate the
    // mdx content inside requestIdleCallback, allowing the page to get to
    // interactive quicker, but the mdx content to hydrate slower.
    useEffect(() => {
        if (lazy) {
            const handle = window.requestIdleCallback(() => {
                setIsReadyToRender(true);
            });
            return () => window.cancelIdleCallback(handle);
        }
    }, []);
    const Content = useMemo(() => {
        // if we're ready to render, we can assemble the component tree and let React do its thing
        // first we set up the scope which has to include the mdx custom
        // create element function as well as any components we're using
        const fullScope = Object.assign({ opts: { ...mdx, ...jsxRuntime } }, { frontmatter }, scope);
        const keys = Object.keys(fullScope);
        const values = Object.values(fullScope);
        // now we eval the source code using a function constructor
        // in order for this to work we need to have React, the mdx createElement,
        // and all our components in scope for the function, which is the case here
        // we pass the names (via keys) in as the function's args, and execute the
        // function with the actual values.
        const hydrateFn = Reflect.construct(Function, keys.concat(`${compiledSource}`));
        return hydrateFn.apply(hydrateFn, values).default;
    }, [scope, compiledSource]);
    if (!isReadyToRender) {
        // If we're not ready to render, return an empty div to preserve SSR'd markup
        return (React.createElement("div", { dangerouslySetInnerHTML: { __html: '' }, suppressHydrationWarning: true }));
    }
    // wrapping the content with MDXProvider will allow us to customize the standard
    // markdown components (such as "h1" or "a") with the "components" object
    const content = (React.createElement(mdx.MDXProvider, { components: components },
        React.createElement(Content, null)));
    // If lazy = true, we need to render a wrapping div to preserve the same markup structure that was SSR'd
    return lazy ? React.createElement("div", null, content) : content;
}

export { MDXRemote };

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:20 (2 by maintainers)

github_iconTop GitHub Comments

9reactions
imtsukicommented, Dec 22, 2022

There is a better temporary solution without the need to downgrade @mdx-js/* to 2.1.5. Just add development: false to the mdxOptions argument within the serialize() call:

 const mdxSource = await serialize(content, {
   mdxOptions: {
     remarkPlugins: [],
     rehypePlugins: [],
+    development: false,
   },
});

In mdx-js/mdx#2045, compiled MDX source will use jsxDEV for rendering in development mode, while in production mode it uses jsx and jsxs. jsxDEV should be imported from react/jsx-dev-runtime, but it is not exported by src/jsx-runtime.cjs. This causes the TypeError: _jsxDEV is not a function error.

9reactions
Tylopiluscommented, Dec 14, 2022

I am not able to use MDXContent in a clientcomp. I am getting TypeError: _jsxDEV is not a function as an error.

impl code:

// Article.tsx
'use client';

import { MDXRemote, MDXRemoteProps } from 'next-mdx-remote';

export function Article({ content }: { content: MDXRemoteProps }) {
  return <MDXRemote {...content} />;
}
// page.tsx
import { serialize } from 'next-mdx-remote/serialize';
import { Article } from '../../../components/Article';
import { getPostBySlug } from '../../../utils/markdownHelper';
type PageProps = {
  params: { post: string };
  searchParams?: { [key: string]: string | string[] | undefined };
};
export default async function Page({ params }: PageProps) {
  const { content } = getPostBySlug(params.post);
  const mdx = await serialize(content);
  return (
    <div>
      <Article content={mdx} />
    </div>
  );
}

using node 18 w/ next@13.0.6 and next-mdx-remote@^4.2.0

Read more comments on GitHub >

github_iconTop Results From Across the Web

Blog - Next.js 13
Next.js 13 introduces layouts, React Server Components, and streaming in the app ... During the alpha, many features are not yet supported.
Read more >
[turbopack] Next.js v13 with Turbopack doesn't support rewrite ...
Error: You are using configuration and/or tools that are not yet supported by Next.js v13 with Turbopack: Unsupported Next.js configuration option(s) ...
Read more >
What's New In Next.js 13? - Smashing Magazine
This feature is actually a big architectural rewrite. It puts React Server Components front and center, leverages a whole new routing system and ......
Read more >
What's New in Next.js 13 - AppSignal Blog
Version 13 of Next.js, a well-established React framework from the Vercel company, was released last week. The announcement was made at the ...
Read more >
NextJS 13 & Why it's complicated - YouTube
NextJS 13 was announced and the hype is real! It changes everything! Right? Well ... not yet. NextJS 13 allows us to experiment...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found