diff --git a/packages/next-mdx/index.js b/packages/next-mdx/index.js index 4d894b9af41d4..fbaa7bc4402f8 100644 --- a/packages/next-mdx/index.js +++ b/packages/next-mdx/index.js @@ -2,6 +2,7 @@ module.exports = (pluginOptions = {}) => (nextConfig = {}) => { const extension = pluginOptions.extension || /\.mdx$/ + const userProvidedMdxOptions = pluginOptions.options const mdxRsOptions = nextConfig?.experimental?.mdxRs const loader = mdxRsOptions @@ -9,16 +10,16 @@ module.exports = loader: require.resolve('./mdx-rs-loader'), options: { providerImportSource: 'next-mdx-import-source-file', - ...pluginOptions.options, + ...userProvidedMdxOptions, // mdxRsOptions is a union of boolean and object type of MdxTransformOptions ...(mdxRsOptions === true ? {} : mdxRsOptions), }, } : { - loader: require.resolve('@mdx-js/loader'), + loader: require.resolve('./mdx-js-loader'), options: { providerImportSource: 'next-mdx-import-source-file', - ...pluginOptions.options, + ...userProvidedMdxOptions, }, } diff --git a/packages/next-mdx/mdx-js-loader.js b/packages/next-mdx/mdx-js-loader.js new file mode 100644 index 0000000000000..4a7ae238b37c3 --- /dev/null +++ b/packages/next-mdx/mdx-js-loader.js @@ -0,0 +1,66 @@ +const mdxLoader = require('@mdx-js/loader') + +function interopDefault(mod) { + return mod.default || mod +} + +async function importPlugin(plugin, projectRoot) { + if (Array.isArray(plugin) && typeof plugin[0] === 'string') { + plugin[0] = interopDefault( + await import(require.resolve(plugin[0], { paths: [projectRoot] })) + ) + } + return plugin +} + +async function getOptions(options, projectRoot) { + const { + recmaPlugins = [], + rehypePlugins = [], + remarkPlugins = [], + ...rest + } = options + + const [updatedRecma, updatedRehype, updatedRemark] = await Promise.all([ + Promise.all( + recmaPlugins.map((plugin) => importPlugin(plugin, projectRoot)) + ), + Promise.all( + rehypePlugins.map((plugin) => importPlugin(plugin, projectRoot)) + ), + Promise.all( + remarkPlugins.map((plugin) => importPlugin(plugin, projectRoot)) + ), + ]) + + return { + ...rest, + recmaPlugins: updatedRecma, + rehypePlugins: updatedRehype, + remarkPlugins: updatedRemark, + } +} + +module.exports = function nextMdxLoader(...args) { + const options = this.getOptions() + const callback = this.async().bind(this) + const loaderContext = this + + getOptions(options, this.context).then((userProvidedMdxOptions) => { + const proxy = new Proxy(loaderContext, { + get(target, prop, receiver) { + if (prop === 'getOptions') { + return () => userProvidedMdxOptions + } + + if (prop === 'async') { + return () => callback + } + + return Reflect.get(target, prop, receiver) + }, + }) + + mdxLoader.call(proxy, ...args) + }) +} diff --git a/test/e2e/app-dir/mdx/app/rehype-plugin/page.mdx b/test/e2e/app-dir/mdx/app/rehype-plugin/page.mdx new file mode 100644 index 0000000000000..daac920da9700 --- /dev/null +++ b/test/e2e/app-dir/mdx/app/rehype-plugin/page.mdx @@ -0,0 +1,5 @@ +# Rehype plugin + +```math +C_L +``` diff --git a/test/e2e/app-dir/mdx/mdx.test.ts b/test/e2e/app-dir/mdx/mdx.test.ts index 516969ad9f27f..3e1afbca60428 100644 --- a/test/e2e/app-dir/mdx/mdx.test.ts +++ b/test/e2e/app-dir/mdx/mdx.test.ts @@ -8,6 +8,7 @@ for (const type of ['with-mdx-rs', 'without-mdx-rs']) { '@next/mdx': 'canary', '@mdx-js/loader': '^2.2.1', '@mdx-js/react': '^2.2.1', + 'rehype-katex': '7.0.1', }, env: { WITH_MDX_RS: type === 'with-mdx-rs' ? 'true' : 'false', @@ -59,6 +60,14 @@ for (const type of ['with-mdx-rs', 'without-mdx-rs']) { '/_next/image?url=%2Ftest.jpg&w=384&q=75' ) }) + + if (type === 'without-mdx-rs') { + it('should run plugins', async () => { + const html = await next.render('/rehype-plugin') + expect(html.includes('C')).toBe(true) + expect(html.includes('L')).toBe(true) + }) + } }) describe('pages directory', () => { diff --git a/test/e2e/app-dir/mdx/next.config.js b/test/e2e/app-dir/mdx/next.config.mjs similarity index 51% rename from test/e2e/app-dir/mdx/next.config.js rename to test/e2e/app-dir/mdx/next.config.mjs index 4485a253ee1f7..f56317a7cadf4 100644 --- a/test/e2e/app-dir/mdx/next.config.js +++ b/test/e2e/app-dir/mdx/next.config.mjs @@ -1,5 +1,10 @@ -const withMDX = require('@next/mdx')({ +import nextMDX from '@next/mdx' +const withMDX = nextMDX({ extension: /\.mdx?$/, + options: { + remarkPlugins: [], + rehypePlugins: [['rehype-katex', { strict: true, throwOnError: true }]], + }, }) /** @@ -12,4 +17,4 @@ const nextConfig = { }, } -module.exports = withMDX(nextConfig) +export default withMDX(nextConfig)