hashicorp / next-mdx-remote

Load MDX content from anywhere
Mozilla Public License 2.0
2.67k stars 140 forks source link

TypeError: _jsx is not a function (most recent versions of Next.js and next-mdx-remote) #350

Open lumenwrites opened 1 year ago

lumenwrites commented 1 year ago

Hi! I have updated my packages to the most recent version, and now I'm getting the following error when I'm trying to render MDX:

TypeError: _jsx is not a function at _createMdxContent

Do you know what could be causing this, and what can I do to debug/fix this?

BRKalow commented 1 year ago

Can you provide a minimal reproduction so we can take a look? What version did you upgrade from?

Thanks.

lumenwrites commented 1 year ago

Can you provide a minimal reproduction so we can take a look?

I'll try to figure it out.

What version did you upgrade from?

next 13.1.1 → 13.2.1
next-mdx-remote ^4.2.0 → ^4.4.0
lumenwrites commented 1 year ago

Aha, looks like this error happens when I use the development: false flag.

Minimal reproduction:

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={{}} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = 'Some **mdx** text, with a component'
  const mdxSource = await serialize(source, {
    mdxOptions: {
      development: false,
    },
  })
  return { props: { source: mdxSource } }
}
BRKalow commented 1 year ago

@lumenwrites that option shouldn't be necessary, it should correctly be determined internally now.

lumenwrites commented 1 year ago

I think I just used this option because it was a workaround to some previous bug I've been dealing with, I don't remember, but everything seems to work fine without it now.

Thanks!

I'll leave this issue open in case you guys want to investigate what's causing it, feel free to close it if you want.

lumenwrites commented 1 year ago

@BRKalow Wait a second, no, I have remembered why I needed this flag.

Now when I'm trying to compile the project, I get the following error:

TypeError: _jsxDEV is not a function

Googling it takes me to this issue where people suggest adding development: false flag as a workaround to this error.

BRKalow commented 1 year ago

This should be resolved by doing a full uninstall and reinstall: https://github.com/hashicorp/next-mdx-remote/issues/307#issuecomment-1379001488

lumenwrites commented 1 year ago

Nope, just tried it, that didn't do it for me. Tried deleting node_modules and package-lock and reinstalling everything, that didn't work either.

lumenwrites commented 1 year ago

A couple of people at the end of the discussion of this issue say that they're still experiencing it as well.

duthanhduoc commented 1 year ago
TypeError: _jsxDEV is not a function
    at _createMdxContent

When i run npm run dev, still work but npm run build got above error

 "next": "^13.2.3"
"next-mdx-remote": "^4.4.1",
"@next/mdx": "^13.2.3",
"@mdx-js/react": "^2.3.0",
"@mdx-js/loader": "^2.3.0",
YannHulot commented 1 year ago

I have the same issue.

I have tried re-installing, uninstalling the dependencies, setting the development flag and basically any workaround mentioned in the other discussions.

Although there is one notable difference with @duthanhduoc , my problem happens when I run next dev but there is no problem when running next build. And the pages are rendered properly in production (hosted on Vercel).

"@next/mdx": "^13.2.3",
"next-mdx-remote": "^4.4.1",
"@mdx-js/loader": "^2.3.0",
"@mdx-js/react": "^2.3.0",
"@next/mdx": "^13.2.3",
BRKalow commented 1 year ago

Thanks y'all. If someone could provide a minimal reproduction (codesandbox or otherwise) that we can take a look at, that would be super helpful 🙏

I believe the issue stems from a transitive dependency of @mdx-js/mdx, which is why a full uninstall and reinstall of next-mdx-remote addresses the issue. If you have a direct dependency on @mdx-js/react however, like @YannHulot does above, you might not get the same result as the version would remain pinned.

lumenwrites commented 1 year ago

Temporary workaround that solves the issue for me:

  const serialized = await serialize(content, {
    mdxOptions: {
      development: process.env.NODE_ENV === 'development',
    }
  })

I'm using next-mdx-remote to process my mdx files and convert them into json. development:true works in development but breaks production (resulting in TypeError: _jsxDEV is not a function during the build) , development:false works in production but breaks development (resulting in TypeError: _jsx is not a function during the dev) . So I just set this flag based on whether I'm working on the website in dev version, or building it on the server to deploy it.

steveruizok commented 1 year ago

Strangely this works fine for me in a a regular nextjs app with next-mdx-remote, but as soon as I switch to using next-remote-watch it breaks (in both development true or false, both _jsx and _jsxDev aren't found).

"next-mdx-remote": "^4.4.1",
"next-remote-watch": "^2.0.0",
"next": "13.2.4",
}
reconbot commented 1 year ago

My personal blog is hitting this issue upgrading from next-mdx-remote from 4.1.0 to 4.4.1 and pnpm. It's not open source but I can give a maintainer read access if it helps.

My package.json "next": "13.2.4", "next-mdx-remote": "4.4.1",

And the pnpm lock says next-mdx-remote is using (the only instance of mdx-js) '@mdx-js/mdx': 2.3.0

@BRKalow what version of @mdx-js/mdx should we be getting?

morulus commented 1 year ago

The problem is in here: https://github.com/mdx-js/mdx/blob/main/packages/mdx/lib/condition.js Unfortunately we cannot specify preferred mode manually. It always looks at NODE_ENV. If you serialize with NODE_ENV development you have to render it also with NODE_ENV development, vice versa.

exil0867 commented 1 year ago

Updating next-mdx-remote from 4.1.0 to 4.4.1 and @mdx-js/react from version 2.2.1 to 2.3.0, on version 13.2.4 of Next.js did the trick.

Before updating, i temporary fixed the issue by setting development to false.

sanny-io commented 1 year ago

Temporary workaround that solves the issue for me:

  const serialized = await serialize(content, {
    mdxOptions: {
      development: process.env.NODE_ENV === 'development',
    }
  })

I'm using next-mdx-remote to process my mdx files and convert them into json. development:true works in development but breaks production (resulting in TypeError: _jsxDEV is not a function during the build) , development:false works in production but breaks development (resulting in TypeError: _jsx is not a function during the dev) . So I just set this flag based on whether I'm working on the website in dev version, or building it on the server to deploy it.

This worked for me. Thank you brother.

vladmoroz commented 1 year ago

This is also not working with Next.js 12.3.1 and "next-mdx-remote": "4.4.1". Full uninstall and reinstall didn't help as well.

Screenshot 2023-05-08 at 11 54 19

Using the development: process.env.NODE_ENV === 'development', workaround yields _jsxDEV is not a function error

Screenshot 2023-05-08 at 11 54 28

package.json:

"next": "12.3.1",
"next-mdx-remote": "4.4.1",
"next-remote-watch": "2.0.0",

Downgrading to 4.2.0 works.

BRKalow commented 1 year ago

Hey all, I believe the problem dependency is estree-util-build-jsx. This needs to be at least v2.1.0. @mdx-js/mdx only specifies ^2.0.0, so it might be the case that your application isn't relying on v2.1.0 here. That's why we suggest the full uninstall / reinstall.

Additionally, if you are also using next-remote-watch, try setting NODE_ENV=development in your package script. The way it's implemented, it looks like NODE_ENV is undefined and so mdx can't properly detect whether it's running in a development or production environment, causing the error:

"dev": "NODE_ENV=development next-remote-watch ./path/to/content"
dimaMachina commented 1 year ago

can confirm that setting resolution to "estree-util-build-jsx": "2.2.2" fix the issue for me

philippkeller commented 1 year ago

To the people who say that the issue can be fixed by upgrading estree-util-build-jsx: can you provide a way to do this? JS beginner here and I see it's a dependency of a dependency -> how could I upgrade this versin?

Anyway - I was able to get working by downgrading next-remote-watch to version 4.1.0

j471n commented 1 year ago

It works for me without adding the development config.

 const mdxSource = await serialize(content, {
    mdxOptions: {
      rehypePlugins: [
        rehypeSlug,
        [rehypeAutolinkHeadings, { behaviour: "wrap" }],
        [rehypePrettyCode, prettyCodeOptions],
      ],
    },
  });

package.json

    "next": "^13.1.6",
    "next-mdx-remote": "^4.4.1",

I want to mention one thing that earlier when I was having this issue so as this comment suggested added the resolutions but if you are using the latest version then remove those resolutions and re-install your packages. It should work fine.

"resolutions": {
-  "@mdx-js/mdx": "2.1.5",
-  "@mdx-js/react": "2.1.5"
}
olayway commented 1 year ago

For me, only the combination of these two worked:

  1. Setting development: process.env.NODE_ENV === 'development' in the mdxOptions
  2. Downgrading next-mdx-remote to 4.2.0.

For context:

  1. I started with this set of dependencies when the TypeError: _jsxDEV is not a function appeared in the console.
flowershow@2.0.3
...
└── next@13.3.0
flowershow@2.0.3
└─┬ next-mdx-remote@4.4.1
  └─┬ @mdx-js/mdx@2.3.0
    └── estree-util-build-jsx@2.2.2
flowershow@2.0.3
└─┬ next-mdx-remote@4.4.1
  └── @mdx-js/react@2.3.0
  1. I tried setting development: process.env.NODE_ENV === 'development' in the mdxOptions. But this resulted in another error: TypeError: _jsx is not a function.
  2. I tried downgrading next-mdx-remote to 4.2.0 (while still having development field in mdxOptions set like in point 2.). And now it worked.
  3. I tried removing the development field from mdxOption now to test if only the package downgrade would work. But it doesn't.
olayway commented 1 year ago

For me, only the combination of these two worked:

  1. Setting development: process.env.NODE_ENV === 'development' in the mdxOptions
  2. Downgrading next-mdx-remote to 4.2.0.

UPDATE: it doesn't work again, no clue why 😭

konsumer commented 1 year ago

This also seems to fail with new nextjs app-router, with 4.2.0 or latest.

page-client.jsx:

'use client'

import { MDXRemote } from 'next-mdx-remote'

const components = {
  Button: ({ children, ...props }) => <button {...props} className='btn'>{children}</button>,
  Image: (props) => <img {...props} />
}

export default function PageBlogArticle ({ post }) {
  if (!post) {
    return 'client'
  }
  console.log(post)
  return (
    <article className='prose m-auto'>
      <h1>{post.title}</h1>
      {post.coverImage && (<img src={post.coverImage} alt={post.title} />)}
      <main>
        {post?.mdx && (<MDXRemote {...post.mdx} components={components} />)}
      </main>
    </article>
  )
}

page.jsx:

import Content from '@slimplate/filesystem'
import site from '../../../../.slimplate.json'
import PageClient from './page-client.jsx'
import { serialize } from 'next-mdx-remote/serialize'

const content = new Content(site.collections.blog, 'blog')

// needed because of bug: https://github.com/hashicorp/next-mdx-remote/issues/350
const mdxOptions = { development: process.env.NODE_ENV === 'development' }

export default async function PageBlogArticle ({ params: { slug }, searchParams }) {
  const post = await content.getByField('slug', slug)
  if (post?.children) {
    post.mdx = await serialize(post.children, { mdxOptions })
  }
  return (
    <PageClient post={post} />
  )
}

export async function generateMetadata ({ params: { slug } }) {
  try {
    const post = await content.getByField('slug', slug)
    return {
      title: `${post.title} - Blog`,
      description: post.description
    }
  } catch (e) {
    return {}
  }
}
lf2lf2kk commented 11 months ago

Temporary workaround that solves the issue for me:

  const serialized = await serialize(content, {
    mdxOptions: {
      development: process.env.NODE_ENV === 'development',
    }
  })

I'm using next-mdx-remote to process my mdx files and convert them into json. development:true works in development but breaks production (resulting in TypeError: _jsxDEV is not a function during the build) , development:false works in production but breaks development (resulting in TypeError: _jsx is not a function during the dev) . So I just set this flag based on whether I'm working on the website in dev version, or building it on the server to deploy it.

It perfectly saved my day, thank you @lumenwrites

HananoshikaYomaru commented 7 months ago

This is also not working with Next.js 12.3.1 and "next-mdx-remote": "4.4.1". Full uninstall and reinstall didn't help as well.

Screenshot 2023-05-08 at 11 54 19

Using the development: process.env.NODE_ENV === 'development', workaround yields _jsxDEV is not a function error

Screenshot 2023-05-08 at 11 54 28

package.json:

"next": "12.3.1",
"next-mdx-remote": "4.4.1",
"next-remote-watch": "2.0.0",

Downgrading to 4.2.0 works.

For me only this work

sharadregoti commented 5 months ago

I was facing this error,

This is my function to convert MDX to HTML

import { compileMDX } from 'next-mdx-remote/rsc'

export const convertMarkdownToHTML = async (postContent: string) => {
    const { frontmatter, content } = await compileMDX({
        source: postContent,
        options: {
            parseFrontmatter: true,
        }
    })

    return { meta: { ...frontmatter }, content }
}

I was getting this error TypeError: _jsx is not a function

I fixed it by moving the above function call from client component to server component at page level

theluk commented 3 months ago

Upgrading to next-mdx-remote: ^5 solved this as for me. So probably better to upgrade than downgrade