Closed karlhorky closed 5 months ago
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": "yarn@1.22.22"
}
Maybe not possible for some projects.
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.
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.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.
- 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 filemdx-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.
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".
Could you just pass the components
prop instead of using @mdx-js/react
?
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:
child.mdx
imported from parent.mdx
)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": "yarn@1.22.22"
}
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.
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.
Initial checklist
Affected packages and versions
@mdx-js/react@3.0.1, next@14.2.4, react@^18, Yarn v1.22.22
Link to runnable example
No response
Steps to reproduce
package.json
using Yarn v1 Workspaces and configuringnohoist
as belowpackages/x
and usecreate-next-app
as below@mdx-js/react
inpackages/x/package.json
(no usage necessary in Next.js app files)yarn workspace x build
and observeCannot 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:
Expected behavior
Adding of
@mdx-js/react
package withnohoist
config should not cause Next.js build to fail withCannot read properties of null (reading 'useContext')
errorActual behavior
Adding of
@mdx-js/react
package withnohoist
config causes Next.js build to fail withCannot read properties of null (reading 'useContext')
errorRuntime
Node v20
Package manager
yarn v1
OS
macOS
Build and bundle tools
Next.js