`components` do not override the built-in react components
jlaramie opened this issue · 4 comments
"@mdx-js/esbuild": "^2.1.1",
"@mdx-js/react": "^2.1.1",
"esbuild": "^0.14.39",
"mdx-bundler": "^9.0.0",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2"
Relevant code or config
// index.tsx
// Created and slightly modified from from https://nextjs.org/docs/api-reference/create-next-app
import { bundleMDX } from "mdx-bundler";
import type { NextPage } from "next";
import Head from "next/head";
import { useMemo } from "react";
import { getMDXComponent } from "mdx-bundler/client/index";
import styles from "../styles/Home.module.css";
import path from "path";
import { MDXProvider } from "@mdx-js/react";
const components = {
"jsx.img": () => {
return <b>This Does Not Work</b>;
},
img: () => {
return <b>This Does Not Work</b>;
},
Img: () => {
return <b>This Does Work</b>;
},
};
const Home: NextPage<{ code: any }> = ({ code }) => {
const MdxComponent = useMemo(() => getMDXComponent(code, {}), [code]);
console.log(code);
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<MDXProvider components={components}>
<MdxComponent components={components} />
</MDXProvider>
</main>
</div>
);
};
export default Home;
export async function getStaticProps() {
if (process.platform === "win32") {
process.env.ESBUILD_BINARY_PATH = path.join(
process.cwd(),
"node_modules",
"esbuild",
"esbuild.exe"
);
} else {
process.env.ESBUILD_BINARY_PATH = path.join(
process.cwd(),
"node_modules",
"esbuild",
"bin",
"esbuild"
);
}
const result = await bundleMDX({
source: `
<div>
does not override: <img src="test.png" />
<br />
does override: <Img src="test.png" />
</div>
`,
mdxOptions: (options) => {
return {
...options,
providerImportSource: "@mdx-js/react",
};
},
});
return {
props: {
code: result.code,
},
};
}
What you did:
I tried to provide my own custom components to override the default ones. Specifically these are MDX / React components like p
and img
and not md paragraphs and ![]()
img links as these types of conversions work.
What happened:
It does not seem possible to directly override a JSX native component like img
. If I name it Img
and pass an Img
component that works.
var Component=(()=>{var p=Object.create;var i=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var u=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty;var x=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports),g=(e,n)=>{for(var t in n)i(e,t,{get:n[t],enumerable:!0})},c=(e,n,t,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of f(n))!a.call(e,r)&&r!==t&&i(e,r,{get:()=>n[r],enumerable:!(s=m(n,r))||s.enumerable});return e};var l=(e,n,t)=>(t=e!=null?p(u(e)):{},c(n||!e||!e.__esModule?i(t,"default",{value:e,enumerable:!0}):t,e)),b=e=>c(i({},"__esModule",{value:!0}),e);var _=x((w,d)=>{d.exports=_jsx_runtime});var v={};g(v,{default:()=>h});var o=l(_());function j(e={}){let{wrapper:n}=e.components||{};return n?(0,o.jsx)(n,Object.assign({},e,{children:(0,o.jsx)(t,{})})):t();function t(){let s=Object.assign({p:"p"},e.components),{Img:r}=s;return r||y("Img",!0,"5:26-5:48"),(0,o.jsxs)("div",{children:[(0,o.jsxs)(s.p,{children:["does not override: ",(0,o.jsx)("img",{src:"test.png"})]}),(0,o.jsx)("br",{}),(0,o.jsxs)(s.p,{children:["does override: ",(0,o.jsx)(r,{src:"test.png"})]})]})}}var h=j;function y(e,n,t){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it."+(t?"\nIt\u2019s referenced in your code at `"+t+"` in `D:\\Repos\\cloud-graphics\\__mdx_bundler_fake_dir__\\_mdx_bundler_entry_point-7484e3ca-f393-4f22-b3f2-48e3853a6125.mdx`":""))}return b(v);})();
Reproduction repository:
https://github.com/jlaramie/mdx-bundler-components-override
Problem description:
Native components like img
should be replaceable with custom components
Suggested solution:
Not sure and still haven't figured out why this works in next-remote-mdx and not mdx-bundler
Related to:
I think you might need to set providerImportSource:
const { code } = await bundleMDX(source, {
...,
xdmOptions: (input, options) => ({
....options,
providerImportSource: '@mdx-js/react'
})
})
I think you might need to set providerImportSource:
const { code } = await bundleMDX(source, { ..., xdmOptions: (input, options) => ({ ....options, providerImportSource: '@mdx-js/react' }) })
@souporserious I had tried this and I just updated my setup to try again and it still doesn't work. I'll update the description of this issue to include the newer versions and sample. I also tried manually wrapping the code with MDXProvider.
Also I updated the repo linked in the description with my latest test. If someone could take a look it has few direct dependencies and shows my issue.
I found the root of the issue mdx-js/mdx#2050
After that pull request got closed I opened another one and had a bigger discussion on it all mdx-js/mdx#2052.
If you want to override native HTML elements you'll need to provide a custom plugin that ensures they get wrapped in the components check.
{
rehypePlugins: [
() => (tree) => {
visit(tree, "mdxJsxTextElement", (node) => {
if (node.data) {
delete node.data._mdxExplicitJsx;
}
});
},
],
}