ReferenceError: process is not defined when importing .tsx files inside MDX file
melosomelo opened this issue ยท 11 comments
mdx-bundler
version:^8.0.1
node
version:v17.3.0
npm
version: Usingyarn
version1.22.17
Relevant code or config
// root/pages/blog/[slug].tsx
export default function BlogArticle({ code, frontmatter }: ArticleProps) {
const { asPath } = useRouter();
const Component = useMemo(() => getMDXComponent(code), [code]); // error happens here
return (...);
}
// ...
const getStaticProps: GetStaticProps<ArticleProps, PathDict> = async (ctx) => {
const { params } = ctx;
const postsDirectory = path.join(__dirname, "..", "..", "..", "..", "posts");
const mdxFile = (
await fs.promises.readFile(path.join(postsDirectory, `${params!.slug}.mdx`))
).toString();
const { code, frontmatter } = await bundleMDX<ArticleFrontmatter>({
source: mdxFile,
cwd: postsDirectory,
xdmOptions(options, frontmatter) {
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMath];
options.rehypePlugins = [
...(options.rehypePlugins ?? []),
rehypeKatex,
rehypeHighlight,
];
return options;
},
});
validateFrontmatter(params!.slug, frontmatter);
if (!frontmatter.published) {
return {
notFound: true,
};
}
const now = new Date().toISOString();
const finalFrontmatter: ArticleMetadata = {
...frontmatter,
publishedOn: frontmatter.publishedOn ?? now,
updatedOn: frontmatter.updatedOn ?? null,
};
return {
props: {
code,
frontmatter: finalFrontmatter,
},
};
};
What you did: I tried to import TSX components into an MDX file.
What happened: I got a client-side error that said ReferenceError: process is not defined
.
Problem description: I'm currently building my blog with MDX and NextJS. I'm on the final stages and I saw that I hadn't configured the part with regards to the path resolution of component imports inside MDX files, so I tried following the docs and used the cwd
option in the bundleMDX
function, which is set to the directory where the MDX files live. All the imports within the MDX files are also relative to the posts directory. If I remove the imports, the error goes away. I don't really know why I'm getting this error and I don't know what I could do to fix it.
The MDX files live in the root/posts
folder. My components folder is root/src/components
. Here are some imports that I tried testing in a MDX file:
import Layout from "../src/components/Layout/index.tsx";
import otherThing from "../src/components/common/CategoryPill/index.tsx";
I managed to make it work, but I'm not quite sure how solid of a solution this is. Would very much like some feedback.
I took a look at the code for getMDXComponent
and saw that it only defines a function based on the code given by esbuild. Considering that process
is a variable defined in the NodeJS environment, it makes sense for the browser to throw an error if the provided code has process
in it. So the problem must have been in the esbuild code given to the browser.
Then I did a bit more digging and found that other people have had this problem with esbuild. The solution I found was to scower the code produced by esbuild for appearances of any process.env
and found out they are all NextJS related.
I then used the property esbuildOptions.define
and replaced each variable that I found:
esbuildOptions(options) {
options.define = {
"process.env.__NEXT_TRAILING_SLASH": '""',
"process.env.__NEXT_CROSS_ORIGIN": '""',
"process.env.__NEXT_I18N_SUPPORT": '""',
"process.env.__NEXT_ROUTER_BASEPATH": '""',
"process.env.__NEXT_SCROLL_RESTORATION": '""',
"process.env.__NEXT_HAS_REWRITES": '""',
};
return options;
},
Is this the default way of doing this? Seems kinda weird to me.
I was able to resolve this by passing the component I was importing to the components
prop on the component returned by getMDXComponent
. Then, no import is necessary.
@darichey doesn't that lead to import overhead? Or are you using some sort of lazy loading?
I was able to resolve this by passing the component I was importing to the
components
prop on the component returned bygetMDXComponent
. Then, no import is necessary.
@darichey can you share share an example of the solution you mention here?
@themikejr Sure, here is the relevant change I made to my site to get things working: darichey/darichey.github.io@a841bc6#diff-94b274c9bf8b1ec216419d94e28d844d4d0f35e18b743214a4769448534c0918
@melosomelo I am not doing anything special, so it's possible. I'm afraid I'm not sure exactly what that entails or how to check. The relevant code is public now (sorry for the delay), so you can check if you'd like. Hopefully we can find a better solution or get a fix!
I went with the approach suggested by @melosomelo but by using the actual values defined by Next:
options.define = {
"process.env.__NEXT_TRAILING_SLASH": JSON.stringify(process.env.__NEXT_TRAILING_SLASH),
"process.env.__NEXT_IMAGE_OPTS": JSON.stringify(process.env.__NEXT_IMAGE_OPTS),
"process.env.__NEXT_REACT_ROOT": JSON.stringify(process.env.__NEXT_REACT_ROOT),
"process.env.__NEXT_OPTIMIZE_FONTS": JSON.stringify(process.env.__NEXT_OPTIMIZE_FONTS)
};
Seems to work so far.
@voluntadpear thanks, it works for me. In my case, I add below in bundleMDX()
:
esbuildOptions: (options) => {
options.define = {
'process.env.__NEXT_TRAILING_SLASH': JSON.stringify(
process.env.__NEXT_TRAILING_SLASH
),
'process.env.__NEXT_IMAGE_OPTS': JSON.stringify(
process.env.__NEXT_IMAGE_OPTS
),
'process.env.__NEXT_REACT_ROOT': JSON.stringify(
process.env.__NEXT_REACT_ROOT
),
'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify(
process.env.__NEXT_OPTIMIZE_FONTS
),
};
return options;
},
Just like FradSer/frad-me@8c8cb42 .
This worked for me
options.define = {
"process.env": JSON.stringify(process.env)
};