diff --git a/packages/loader/readme.md b/packages/loader/readme.md index 4eaec6f4e..8b1542450 100644 --- a/packages/loader/readme.md +++ b/packages/loader/readme.md @@ -31,14 +31,14 @@ module: { // … { test: /\.mdx$/, - use: ['babel-loader', '@mdx-js/loader'] + use: ['@mdx-js/loader'] } ] } ``` -You’ll probably want to configure Babel to use `@babel/preset-react` or so, but -that’s not required. +You might want to add `babel-loader` there too if you have modern JS features +that you want to compile down. All options given to `mdx-js/loader`, except for `renderer` (see below), are passed to MDX itself: diff --git a/packages/loader/test/index.test.js b/packages/loader/test/index.test.js index e073eb0a7..fa70f0393 100644 --- a/packages/loader/test/index.test.js +++ b/packages/loader/test/index.test.js @@ -20,20 +20,7 @@ const transform = (filePath, options) => { rules: [ { test: /\.mdx$/, - use: [ - { - loader: 'babel-loader', - options: { - configFile: false, - plugins: [ - '@babel/plugin-transform-runtime', - '@babel/plugin-syntax-jsx', - '@babel/plugin-transform-react-jsx' - ] - } - }, - {loader: path.resolve(__dirname, '..'), options} - ] + use: [{loader: path.resolve(__dirname, '..'), options}] } ] } @@ -64,13 +51,8 @@ const run = value => { // return new Function(val)().default // Replace import/exports w/ parameters and return value. const val = value - .replace( - /import _objectWithoutProperties from "@babel\/runtime\/helpers\/objectWithoutProperties";/, - '' - ) - .replace(/import _extends from "@babel\/runtime\/helpers\/extends";/, '') - .replace(/import React from 'react';/, '') - .replace(/import \{ mdx } from '@mdx-js\/react';/, '') + .replace(/import React from 'react'/, '') + .replace(/import \{mdx} from '@mdx-js\/react'/, '') .replace(/export default/, 'return') // eslint-disable-next-line no-new-func diff --git a/packages/mdx/estree-to-js.js b/packages/mdx/estree-to-js.js index f05a5c9c9..9b86628b5 100644 --- a/packages/mdx/estree-to-js.js +++ b/packages/mdx/estree-to-js.js @@ -20,7 +20,7 @@ const customGenerator = Object.assign({}, astring.baseGenerator, { }) function estreeToJs(estree) { - return astring.generate(estree, {generator: customGenerator}) + return astring.generate(estree, {generator: customGenerator, comments: true}) } // `attr="something"` diff --git a/packages/mdx/index.js b/packages/mdx/index.js index b5ea9a823..433e10a91 100644 --- a/packages/mdx/index.js +++ b/packages/mdx/index.js @@ -6,10 +6,6 @@ const minifyWhitespace = require('rehype-minify-whitespace') const mdxAstToMdxHast = require('./mdx-ast-to-mdx-hast') const mdxHastToJsx = require('./mdx-hast-to-jsx') -const pragma = `/* @jsxRuntime classic */ -/* @jsx mdx */ -/* @jsxFrag mdx.Fragment */` - function createMdxAstCompiler(options = {}) { return unified() .use(remarkParse) @@ -37,13 +33,13 @@ function createConfig(mdx, options) { } function sync(mdx, options = {}) { - const file = createCompiler(options).processSync(createConfig(mdx, options)) - return pragma + '\n' + String(file) + return String(createCompiler(options).processSync(createConfig(mdx, options))) } async function compile(mdx, options = {}) { - const file = await createCompiler(options).process(createConfig(mdx, options)) - return pragma + '\n' + String(file) + return String( + await createCompiler(options).process(createConfig(mdx, options)) + ) } module.exports = compile diff --git a/packages/mdx/mdx-hast-to-jsx.js b/packages/mdx/mdx-hast-to-jsx.js index e739e258d..6a56169e2 100644 --- a/packages/mdx/mdx-hast-to-jsx.js +++ b/packages/mdx/mdx-hast-to-jsx.js @@ -1,5 +1,6 @@ const toEstree = require('hast-util-to-estree') const walk = require('estree-walker').walk +const buildJsx = require('estree-util-build-jsx') const periscopic = require('periscopic') const estreeToJs = require('./estree-to-js') @@ -7,6 +8,7 @@ function serializeEstree(estree, options) { const { // Default options skipExport = false, + keepJsx = false, wrapExport } = options @@ -150,6 +152,13 @@ function serializeEstree(estree, options) { exports.push({type: 'ExportDefaultDeclaration', declaration: declaration}) } + // Add JSX pragma comments. + estree.comments.unshift( + {type: 'Block', value: '@jsxRuntime classic'}, + {type: 'Block', value: '@jsx mdx'}, + {type: 'Block', value: '@jsxFrag mdx.Fragment'} + ) + estree.body = [ ...createMakeShortcodeHelper( magicShortcodes, @@ -159,6 +168,10 @@ function serializeEstree(estree, options) { ...exports ] + if (!keepJsx) { + buildJsx(estree) + } + return estreeToJs(estree) } diff --git a/packages/mdx/package.json b/packages/mdx/package.json index c25bb84fc..e1c0d1984 100644 --- a/packages/mdx/package.json +++ b/packages/mdx/package.json @@ -47,6 +47,7 @@ "astring": "^1.4.0", "detab": "^2.0.0", "estree-walker": "^2.0.0", + "estree-util-build-jsx": "^1.0.0", "hast-util-to-estree": "^1.1.0", "mdast-util-to-hast": "^10.1.0", "periscopic": "^2.0.0", diff --git a/packages/mdx/test/index.test.js b/packages/mdx/test/index.test.js index 6ad30e603..84c361a82 100644 --- a/packages/mdx/test/index.test.js +++ b/packages/mdx/test/index.test.js @@ -19,7 +19,6 @@ const run = async (value, options = {}) => { const {code} = await babel.transformAsync(doc, { configFile: false, plugins: [ - '@babel/plugin-transform-react-jsx', path.resolve(__dirname, '../../babel-plugin-remove-export-keywords') ] }) @@ -30,13 +29,19 @@ const run = async (value, options = {}) => { } describe('@mdx-js/mdx', () => { - it('should generate JSX', async () => { + it('should generate JS (by default)', async () => { const result = await mdx('Hello World') + expect(result).toMatch(/mdx\("p", null, "Hello World"\)/) + }) + + it('should generate JSX (`keepJsx: true`)', async () => { + const result = await mdx('Hello World', {keepJsx: true}) + expect(result).toMatch(/

\{"Hello World"\}<\/p>/) }) - it('should generate runnable JSX', async () => { + it('should generate runnable JS', async () => { const Content = await run('Hello World') expect(renderToStaticMarkup()).toEqual( @@ -396,7 +401,7 @@ describe('@mdx-js/mdx', () => { rehypePlugins: [plugin] }) - expect(result).toMatch(/export const A = \(\) => !<\/b>/) + expect(result).toMatch(/export const A = \(\) => mdx\("b", null, "!"\)/) }) it('should crash on incorrect exports', async () => { @@ -711,24 +716,24 @@ describe('@mdx-js/mdx', () => { describe('default', () => { it('should be async', async () => { - expect(mdx('x')).resolves.toMatch(/

{"x"}<\/p>/) + expect(mdx('x')).resolves.toMatch(/mdx\("p", null, "x"\)/) }) it('should support `remarkPlugins`', async () => { expect(mdx('$x$', {remarkPlugins: [math]})).resolves.toMatch( - /className="math math-inline"/ + /className: "math math-inline"/ ) }) }) describe('sync', () => { it('should be sync', () => { - expect(mdx.sync('x')).toMatch(/

{"x"}<\/p>/) + expect(mdx.sync('x')).toMatch(/mdx\("p", null, "x"\)/) }) it('should support `remarkPlugins`', () => { expect(mdx.sync('$x$', {remarkPlugins: [math]})).toMatch( - /className="math math-inline"/ + /className: "math math-inline"/ ) }) }) @@ -772,7 +777,7 @@ describe('createMdxAstCompiler', () => { describe('createCompiler', () => { it('should create a unified processor', () => { expect(String(mdx.createCompiler().processSync('x'))).toMatch( - /

{"x"}<\/p>/ + /mdx\("p", null, "x"\)/ ) }) }) @@ -817,6 +822,6 @@ describe('mdx-hast-to-jsx', () => { const doc = unified().use(toJsx).stringify(tree) expect(doc).toMatch(/export default MDXContent/) - expect(doc).toMatch(/\{"a"}<\/x>/) + expect(doc).toMatch(/mdx\("x", null, "a"\)/) }) }) diff --git a/packages/preact/test/test.js b/packages/preact/test/test.js index dd715e064..f80d9f0e8 100644 --- a/packages/preact/test/test.js +++ b/packages/preact/test/test.js @@ -15,7 +15,6 @@ const run = async value => { const {code} = await babelTransform(doc, { configFile: false, plugins: [ - '@babel/plugin-transform-react-jsx', path.resolve(__dirname, '../../babel-plugin-remove-export-keywords') ] }) diff --git a/packages/react/test/test.js b/packages/react/test/test.js index 3bf34409d..6901bf585 100644 --- a/packages/react/test/test.js +++ b/packages/react/test/test.js @@ -15,7 +15,6 @@ const run = async value => { const {code} = await babelTransform(doc, { configFile: false, plugins: [ - '@babel/plugin-transform-react-jsx', path.resolve(__dirname, '../../babel-plugin-remove-export-keywords') ] }) diff --git a/packages/runtime/package.json b/packages/runtime/package.json index cd8a6defd..43a8fc9a5 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -53,8 +53,7 @@ }, "dependencies": { "@mdx-js/mdx": "^2.0.0-next.8", - "@mdx-js/react": "^2.0.0-next.8", - "buble-jsx-only": "^0.19.8" + "@mdx-js/react": "^2.0.0-next.8" }, "devDependencies": { "microbundle": "^0.12.0", diff --git a/packages/runtime/src/index.js b/packages/runtime/src/index.js index 5a0967174..aab92f4c6 100644 --- a/packages/runtime/src/index.js +++ b/packages/runtime/src/index.js @@ -1,5 +1,4 @@ import React from 'react' -import {transform} from 'buble-jsx-only' import mdx from '@mdx-js/mdx' import {MDXProvider, mdx as createElement} from '@mdx-js/react' @@ -25,7 +24,7 @@ export default ({ ...scope } - const jsx = mdx + const js = mdx .sync(children, { remarkPlugins, rehypePlugins, @@ -33,13 +32,11 @@ export default ({ }) .trim() - const code = transform(jsx, {objectAssign: 'Object.assign'}).code - const keys = Object.keys(fullScope) const values = Object.values(fullScope) // eslint-disable-next-line no-new-func - const fn = new Function('React', ...keys, `${code}\n\n${suffix}`) + const fn = new Function('React', ...keys, `${js}\n\n${suffix}`) return fn(React, ...values) } diff --git a/packages/vue-loader/index.js b/packages/vue-loader/index.js index becb39b09..397e02472 100644 --- a/packages/vue-loader/index.js +++ b/packages/vue-loader/index.js @@ -38,7 +38,8 @@ async function mdxLoader(content) { result = await mdx(content, { ...options, skipExport: true, - mdxFragment: false + mdxFragment: false, + keepJsx: true }) } catch (err) { return callback(err) diff --git a/packages/vue/test/test.js b/packages/vue/test/test.js index ac9894122..4f5981fb3 100644 --- a/packages/vue/test/test.js +++ b/packages/vue/test/test.js @@ -7,7 +7,11 @@ import {MDXProvider, mdx} from '../src' const run = async value => { // Turn the serialized MDX code into serialized JSX… - const doc = await mdxTransform(value, {skipExport: true, mdxFragment: false}) + const doc = await mdxTransform(value, { + skipExport: true, + mdxFragment: false, + keepJsx: true + }) // …and that into serialized JS. const {code} = await babelTransform(doc, { diff --git a/yarn.lock b/yarn.lock index 87d77cb45..45b420b85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4985,11 +4985,6 @@ accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-dynamic-import@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" - integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== - acorn-globals@^4.1.0, acorn-globals@^4.3.0: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" @@ -5006,7 +5001,7 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.0.0, acorn-jsx@^5.0.1, acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: +acorn-jsx@^5.0.0, acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== @@ -5026,7 +5021,7 @@ acorn@^5.5.3: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== -acorn@^6.0.1, acorn@^6.0.4, acorn@^6.0.7, acorn@^6.1.1, acorn@^6.2.1, acorn@^6.4.1: +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.0.7, acorn@^6.2.1, acorn@^6.4.1: version "6.4.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== @@ -6590,19 +6585,6 @@ btoa-lite@^1.0.0: resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= -buble-jsx-only@^0.19.8: - version "0.19.8" - resolved "https://registry.yarnpkg.com/buble-jsx-only/-/buble-jsx-only-0.19.8.tgz#6e3524aa0f1c523de32496ac9aceb9cc2b493867" - integrity sha512-7AW19pf7PrKFnGTEDzs6u9+JZqQwM1VnLS19OlqYDhXomtFFknnoQJAPHeg84RMFWAvOhYrG7harizJNwUKJsA== - dependencies: - acorn "^6.1.1" - acorn-dynamic-import "^4.0.0" - acorn-jsx "^5.0.1" - chalk "^2.4.2" - magic-string "^0.25.3" - minimist "^1.2.0" - regexpu-core "^4.5.4" - buble@0.19.6: version "0.19.6" resolved "https://registry.yarnpkg.com/buble/-/buble-0.19.6.tgz#915909b6bd5b11ee03b1c885ec914a8b974d34d3" @@ -10515,6 +10497,14 @@ estree-util-attach-comments@^1.0.0: resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-1.0.0.tgz#51d280e458ce85dec0b813bd96d2ce98eae8a3f2" integrity sha512-sL7dTwFGqzelPlB56lRZY1CC/yDxCe365WQpxNd49ispL40Yv8Tv4SmteGbvZeFwShOOVKfMlo4jrVvwoaMosA== +estree-util-build-jsx@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-1.0.0.tgz#80df2b0d8fbdfa7e2e7b16c02d007062af2f0ed0" + integrity sha512-OVzOP9kjOBO7xiN+A7mMjfJQyIxf+prnohyg1afd3sVHW1GTOY55SfyeKvPO+C0Ej7crP1NG/gFMmowxcKy6kw== + dependencies: + estree-util-is-identifier-name "^1.0.0" + estree-walker "^2.0.0" + estree-util-is-identifier-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-1.0.0.tgz#3f9b8ae3e9d661858752ce73450f37dca160f029" @@ -16615,7 +16605,7 @@ magic-string@^0.22.4: dependencies: vlq "^0.2.2" -magic-string@^0.25.1, magic-string@^0.25.2, magic-string@^0.25.3: +magic-string@^0.25.1, magic-string@^0.25.2: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== @@ -21821,7 +21811,7 @@ regexpp@^3.0.0, regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== -regexpu-core@^4.2.0, regexpu-core@^4.5.4, regexpu-core@^4.7.1: +regexpu-core@^4.2.0, regexpu-core@^4.7.1: version "4.7.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==