Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nohoist @mdx-js/react with Next.js: Cannot read properties of null (reading 'useContext') #2499

Closed
4 tasks done
karlhorky opened this issue Jun 25, 2024 · 9 comments
Closed
4 tasks done
Labels
🙅 no/wontfix This is not (enough of) an issue for this project

Comments

@karlhorky
Copy link
Contributor

Initial checklist

Affected packages and versions

@mdx-js/[email protected], [email protected], react@^18, Yarn v1.22.22

Link to runnable example

No response

Steps to reproduce

  1. Create a folder with a package.json using Yarn v1 Workspaces and configuring nohoist as below
  2. Create dirs packages/x and use create-next-app as below
  3. Add @mdx-js/react in packages/x/package.json (no usage necessary in Next.js app files)
  4. Run yarn workspace x build and observe Cannot read properties of null (reading 'useContext') error 💥

Reproduction repository: https://github.com/karlhorky/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property

Reproduction commands logs:

➜  p mkdir repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property
➜  p cd repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property

➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property echo '{"private":true,"workspaces":{"packages":["packages/*"],"nohoist":["**/@mdx-js/react","**/@mdx-js/react/**/*"]},"packageManager":"[email protected]"}' > package.json
➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property cat package.json
{
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**/@mdx-js/react",
      "**/@mdx-js/react/**/*"
    ]
  },
  "packageManager": "[email protected]"
}

➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property mkdir -p packages/x
➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property cd packages/x

➜  x yarn create next-app . --app --no-turbo --no-src-dir --no-eslint --import-alias @/\* --no-tailwind

...

➜  x yarn add @mdx-js/react

...

➜  x cd ../..
➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property yarn install

...

➜  repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property yarn workspace x build
yarn workspace v1.22.22
yarn run v1.22.22
$ next build
  ▲ Next.js 14.2.4

   Creating an optimized production build ...
 ✓ Compiled successfully
 ✓ Linting and checking validity of types    
 ✓ Collecting page data    
   Generating static pages (0/5)  [=   ]TypeError: Cannot read properties of null (reading 'useContext')
    at exports.useContext (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/node_modules/react/cjs/react.production.min.js:24:495)
    at h (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/.next/server/pages/_error.js:1:5995)
    at Wc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at bd (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:217)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:71:145)

Error occurred prerendering page "/500". Read more: https://nextjs.org/docs/messages/prerender-error

TypeError: Cannot read properties of null (reading 'useContext')
    at exports.useContext (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/node_modules/react/cjs/react.production.min.js:24:495)
    at h (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/.next/server/pages/_error.js:1:5995)
    at Wc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at bd (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:217)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:71:145)
TypeError: Cannot read properties of null (reading 'useContext')
    at exports.useContext (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/node_modules/react/cjs/react.production.min.js:24:495)
    at h (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/.next/server/pages/_error.js:1:5995)
    at Wc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at bd (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:217)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:71:145)

Error occurred prerendering page "/404". Read more: https://nextjs.org/docs/messages/prerender-error

TypeError: Cannot read properties of null (reading 'useContext')
    at exports.useContext (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/node_modules/react/cjs/react.production.min.js:24:495)
    at h (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/packages/x/.next/server/pages/_error.js:1:5995)
    at Wc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at bd (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
    at Z (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:217)
    at $c (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
    at Zc (/Users/k/p/repro-mdx-react-next-js-nohoist-cannot-read-usecontext-property/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:71:145)
 ✓ Generating static pages (5/5)

> Export encountered errors on following paths:
        /_error: /404
        /_error: /500
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed.
Exit code: 1

Expected behavior

Adding of @mdx-js/react package with nohoist config should not cause Next.js build to fail with Cannot read properties of null (reading 'useContext') error

Actual behavior

Adding of @mdx-js/react package with nohoist config causes Next.js build to fail with Cannot read properties of null (reading 'useContext') error

Runtime

Node v20

Package manager

yarn v1

OS

macOS

Build and bundle tools

Next.js

@karlhorky
Copy link
Contributor Author

karlhorky commented Jun 25, 2024

Workaround 1 (remove nohoist config)

Remove the nohoist config in the root package.json Yarn v1 Workspaces config and then run yarn install again:

package.json

{
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
-      "**/@mdx-js/react",
-      "**/@mdx-js/react/**/*"
    ]
  },
  "packageManager": "[email protected]"
}

Maybe not possible for some projects.

@ChristianMurphy
Copy link
Member

Hey @karlhorky! 👋
Taking a step back, mdx is generally designed to work with npm.
With other package managers with different resolution strategies like plug and play and non-hoisted, your mileage may vary.

Why are you using a non-hoisted strategy in the first place?
My guess is that you have a conflicting version in dependencies, with npm you can find these with npm ls {package name} likely react.
I think the yarn equivalent is yarn list --pattern react, I suspect you have duplicate/conflicting versions.

Duplicate copies of react always causes problems, that is not mdx specific.

@remcohaszing
Copy link
Member

remcohaszing commented Jun 25, 2024

  1. You shouldn’t use Yarn 1. It’s old, unmaintained, and known to have bugs.
  2. Next.js app router does not support useContext(), therefor it doesn’t support @mdx-js/react. Create a file mdx-components.tsx in your package root instead. The best documentation for that can be found in https://github.com/mdx-js/mdx-analyzer#mdxprovidedcomponents.
  3. The Next.js team just keeps ignoring to enhance the MDX experience for Next.js or dismisses them based on falsehoods. (Add a fallback for the mdx-components file vercel/next.js#59693, examples(with-mdx): update to MDX 3 vercel/next.js#62503, Fix the mdx-components examples vercel/next.js#64769)

@karlhorky
Copy link
Contributor Author

karlhorky commented Jun 25, 2024

Thanks for the tips so far!

I'm using nohoist because we have multiple versions of @mdx-js/react and react in the monorepo, which are causing conflicts when the different apps are built.

  1. You shouldn’t use Yarn 1. It’s old, unmaintained, and known to have bugs.

Indeed, I would love to switch off it. This large monorepo is one of our last projects using it. For now, it's just working around the problems :)

2. Next.js app router does not support useContext(), therefor it doesn’t support @mdx-js/react. Create a file mdx-components.tsx in your package root instead. The best documentation for that can be found in mdx-js/mdx-analyzer#mdxprovidedcomponents.

Ah, Next.js App Router does support useContext() (in Client Components). We already have a better version than this working with mdx-bundler.

It's just crashing currently because we're recursively rendering .mdx files which import other .mdx files, which requires @mdx-js/react, and we're using nohoist to try to avoid the conflicts with the other versions in the monorepo.

@karlhorky
Copy link
Contributor Author

karlhorky commented Jun 25, 2024

It's indeed probably caused by duplicate react packages in the different node_modules directories.

I'll see if I can find one more workaround and then we can close it as "working as intended".

@remcohaszing
Copy link
Member

Could you just pass the components prop instead of using @mdx-js/react?

@karlhorky
Copy link
Contributor Author

karlhorky commented Jun 25, 2024

Oh yeah, actually if either of you would know a simpler way of achieving recursive rendering of MDX files (.mdx files which import other .mdx files, which should also have the same components context), then that would be amazing!

Currently the only one we've seen working is mdx-bundler (we need programmatic access - cannot use app/*/*.mdx directly - since we render MDX content from database dynamically based on slug and add other things to the JSX):

For an example of a "simpler" approach, I would ideally like to an approach like this (similar to the rsc-mdx library by @zhangyu1818), to dynamically evaluate() in RSC:

import { evaluate, type EvaluateOptions } from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'
import remarkGfm from 'remark-gfm';

export async function MDX(props: MDXProps) {
  const { source, ...rest } = props
  const { default: MDXContent } = await evaluate(source, {
    useMDXComponents: () => ({ ... }),
    remarkPlugins: [remarkGfm],
    rehypePlugins: [],
    ...rest,
    ...(runtime as Pick<EvaluateOptions, 'Fragment' | 'jsx' | 'jsxs'>),
  })

  return <MDXContent />
}

But it has problems with importing the child .mdx files, if I remember correctly:

  1. not being able to resolve the imported files (eg. child.mdx imported from parent.mdx)
  2. not adding the components in the MDX context to the child imported files

@karlhorky
Copy link
Contributor Author

Workaround 2 (add nohoist config for react)

To deduplicate the version of the react package (one version in node_modules/react, one version in packages/x/node_modules/react), another way to avoid the conflicts is to configure nohoist also for react

package.json

{
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**/@mdx-js/react",
      "**/@mdx-js/react/**/*",
+     "**/react"
    ]
  },
  "packageManager": "[email protected]"
}

This will ensure there is only the react in packages/x/node_modules/react and that this is the version being used in the build.

@karlhorky
Copy link
Contributor Author

Since it appears that duplicate copies of the react package are causing this problem (caused by the hoisting behavior of Yarn v1 nohoist), I will close this as "working as intended" or "wontfix".

Anyone else running into this Cannot read properties of null (reading 'useContext') error can consider if it is a problem caused by duplicate copies of react, especially in multiple node_modules locations, common in monorepos.

@ChristianMurphy ChristianMurphy added the 🙅 no/wontfix This is not (enough of) an issue for this project label Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🙅 no/wontfix This is not (enough of) an issue for this project
Development

No branches or pull requests

3 participants