mirror of
https://github.com/mdx-js/mdx.git
synced 2024-09-19 03:17:10 +03:00
Add support for React 18 (#1808)
Reviewed-by: Christian Murphy <christian.murphy.42@gmail.com>
This commit is contained in:
parent
4afc80ca3c
commit
00b1db10d7
@ -1,6 +1,6 @@
|
||||
import React, {useState, useMemo, createElement, memo, useCallback} from 'react'
|
||||
import {useDebounceFn} from 'ahooks'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
import {VFile} from 'vfile'
|
||||
import {VFileMessage} from 'vfile-message'
|
||||
import {statistics} from 'vfile-statistics'
|
||||
|
@ -402,7 +402,7 @@ You can update your code as follows:
|
||||
After:
|
||||
|
||||
```js path="new.js"
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
import * as provider from '@mdx-js/react'
|
||||
import {evaluate} from '@mdx-js/mdx'
|
||||
|
||||
@ -431,7 +431,7 @@ Using Emotion as an example:
|
||||
|
||||
```js path="new-emotion.js"
|
||||
// …
|
||||
import * as runtime from '@emotion/react/jsx-runtime.js'
|
||||
import * as runtime from '@emotion/react/jsx-runtime'
|
||||
// …
|
||||
```
|
||||
|
||||
|
614
package-lock.json
generated
614
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -172,6 +172,7 @@
|
||||
],
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"import/extensions": "off",
|
||||
"node/file-extension-in-import": "off",
|
||||
"react/prop-types": "off",
|
||||
"unicorn/prefer-node-protocol": "off",
|
||||
|
@ -50,8 +50,8 @@
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/unist": "^2.0.0",
|
||||
"esbuild": "^0.13.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"vfile-message": "^3.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -59,8 +59,8 @@
|
||||
"babel-loader": "^8.0.0",
|
||||
"preact": "^10.0.0",
|
||||
"preact-render-to-string": "^5.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"vue": "^3.0.0",
|
||||
"webpack": "^5.0.0"
|
||||
},
|
||||
|
@ -64,8 +64,8 @@
|
||||
"nanoid": "^3.0.0",
|
||||
"preact": "^10.0.0",
|
||||
"preact-render-to-string": "^5.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"rehype-katex": "^6.0.0",
|
||||
"rehype-raw": "^6.0.0",
|
||||
"remark-frontmatter": "^4.0.0",
|
||||
|
@ -688,7 +688,7 @@ They come from an automatic JSX runtime that you must import yourself.
|
||||
<summary>Example</summary>
|
||||
|
||||
```js
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
|
||||
const {default: Content} = await evaluate('# hi', {...runtime, ...otherOptions})
|
||||
```
|
||||
@ -704,7 +704,7 @@ Needed if you want to support a provider.
|
||||
|
||||
```js
|
||||
import * as provider from '@mdx-js/react'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
|
||||
const {default: Content} = await evaluate('# hi', {...provider, ...runtime, ...otherOptions})
|
||||
```
|
||||
@ -723,7 +723,7 @@ that was exported from the MDX file available too.
|
||||
Assuming the contents of `example.mdx` from [§ Use][use] was in `file`, then:
|
||||
|
||||
```js
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
import {evaluate} from '@mdx-js/mdx'
|
||||
|
||||
console.log(await evaluate(file, {...runtime}))
|
||||
|
@ -145,10 +145,10 @@ test('compile', async () => {
|
||||
'should support the automatic runtime (`@jsxRuntime`)'
|
||||
)
|
||||
|
||||
console.log(
|
||||
'\nnote: the next deprecation is expected (preact is missing an export map)\n'
|
||||
)
|
||||
|
||||
// console.log(
|
||||
// '\nnote: the next deprecation is expected (preact is missing an export map)\n'
|
||||
// )
|
||||
//
|
||||
// To do: re-enable when `preact/compat` has a correct export map.
|
||||
// assert.equal(
|
||||
// render(
|
||||
@ -178,12 +178,7 @@ test('compile', async () => {
|
||||
|
||||
assert.equal(
|
||||
render(
|
||||
h(
|
||||
await run(compileSync('<>1</>', {jsxImportSource: 'preact'}), {
|
||||
keepImport: true
|
||||
}),
|
||||
{}
|
||||
)
|
||||
h(await run(compileSync('<>1</>', {jsxImportSource: 'preact'})), {})
|
||||
),
|
||||
'1',
|
||||
'should support `jsxImportSource` for `preact`'
|
||||
@ -198,8 +193,7 @@ test('compile', async () => {
|
||||
).replace(
|
||||
/\/jsx-runtime(?=["'])/g,
|
||||
'$&/dist/emotion-react-jsx-runtime.cjs.prod.js'
|
||||
),
|
||||
{keepImport: true}
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
@ -947,7 +941,7 @@ test('markdown (GFM, with `remark-gfm`)', async () => {
|
||||
await run(compileSync('* [x] a\n* [ ] b', {remarkPlugins: [remarkGfm]}))
|
||||
)
|
||||
),
|
||||
'<ul class="contains-task-list">\n<li class="task-list-item"><input type="checkbox" checked="" disabled=""/> a</li>\n<li class="task-list-item"><input type="checkbox" disabled=""/> b</li>\n</ul>',
|
||||
'<ul class="contains-task-list">\n<li class="task-list-item"><input type="checkbox" disabled="" checked=""/> a</li>\n<li class="task-list-item"><input type="checkbox" disabled=""/> b</li>\n</ul>',
|
||||
'should support task lists (`* [x]` -> `input`)'
|
||||
)
|
||||
|
||||
@ -1322,10 +1316,7 @@ test('source maps', async () => {
|
||||
Buffer.from(JSON.stringify(file.map)).toString('base64') +
|
||||
'\n'
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(base, 'sourcemap.js'),
|
||||
String(file).replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
)
|
||||
await fs.writeFile(path.join(base, 'sourcemap.js'), String(file))
|
||||
|
||||
const Content = /** @type {MDXContent} */ (
|
||||
/* @ts-expect-error file is dynamically generated */
|
||||
@ -1356,32 +1347,21 @@ test.run()
|
||||
/**
|
||||
*
|
||||
* @param {VFileCompatible} input
|
||||
* @param {{keepImport?: boolean}} [options]
|
||||
* @return {Promise<MDXContent>}
|
||||
*/
|
||||
async function run(input, options = {}) {
|
||||
return (await runWhole(input, options)).default
|
||||
async function run(input) {
|
||||
return (await runWhole(input)).default
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {VFileCompatible} input
|
||||
* @param {{keepImport?: boolean}} [options]
|
||||
* @return {Promise<MDXModule>}
|
||||
*/
|
||||
async function runWhole(input, options = {}) {
|
||||
async function runWhole(input) {
|
||||
const name = 'fixture-' + nanoid().toLowerCase() + '.js'
|
||||
const fp = path.join('test', 'context', name)
|
||||
let doc = String(input)
|
||||
|
||||
// Extensionless imports only work in faux-ESM (webpack and such),
|
||||
// *not* in Node by default: *except* if there’s an export map defined
|
||||
// in `package.json`.
|
||||
// React doesn’t have one yet (it’s on `master` but not yet released), so add
|
||||
// the extension for ’em:
|
||||
if (!options.keepImport) {
|
||||
doc = doc.replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
}
|
||||
const doc = String(input)
|
||||
|
||||
await fs.writeFile(fp, doc)
|
||||
|
||||
|
@ -1,5 +1,14 @@
|
||||
/**
|
||||
* @typedef {import('@mdx-js/mdx/lib/compile.js').CompileOptions} CompileOptions
|
||||
*
|
||||
* @typedef LoaderOptions
|
||||
* @property {boolean} [fixRuntimeWithoutExportMap=true]
|
||||
* Several JSX runtimes, notably React and Emotion, don’t yet have a proper
|
||||
* export map set up.
|
||||
* Export maps are needed to map `xxx/jsx-runtime` to an actual file in ESM.
|
||||
* This option fixes React et al by turning those into `xxx/jsx-runtime.js`.
|
||||
*
|
||||
* @typedef {CompileOptions & LoaderOptions} Options
|
||||
*/
|
||||
|
||||
import {promises as fs} from 'node:fs'
|
||||
@ -11,10 +20,18 @@ import {createFormatAwareProcessors} from '@mdx-js/mdx/lib/util/create-format-aw
|
||||
/**
|
||||
* Create smart processors to handle different formats.
|
||||
*
|
||||
* @param {CompileOptions} [options]
|
||||
* @param {Options} [options]
|
||||
*/
|
||||
export function createLoader(options) {
|
||||
export function createLoader(options = {}) {
|
||||
const {extnames, process} = createFormatAwareProcessors(options)
|
||||
let fixRuntimeWithoutExportMap = options.fixRuntimeWithoutExportMap
|
||||
|
||||
if (
|
||||
fixRuntimeWithoutExportMap === null ||
|
||||
fixRuntimeWithoutExportMap === undefined
|
||||
) {
|
||||
fixRuntimeWithoutExportMap = true
|
||||
}
|
||||
|
||||
return {load, getFormat, transformSource}
|
||||
|
||||
@ -30,16 +47,16 @@ export function createLoader(options) {
|
||||
return defaultLoad(url, context, defaultLoad)
|
||||
}
|
||||
|
||||
const fp = fileURLToPath(new URL(url))
|
||||
const value = await fs.readFile(fp)
|
||||
/* eslint-disable-next-line security/detect-non-literal-fs-filename */
|
||||
const value = await fs.readFile(fileURLToPath(new URL(url)))
|
||||
const file = await process(new VFile({value, path: new URL(url)}))
|
||||
let source = String(file)
|
||||
|
||||
// V8 on Erbium.
|
||||
/* c8 ignore next 2 */
|
||||
return {
|
||||
format: 'module',
|
||||
source: String(file).replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
if (fixRuntimeWithoutExportMap) {
|
||||
source = String(file).replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
}
|
||||
|
||||
return {format: 'module', source}
|
||||
}
|
||||
|
||||
// Pre version 17.
|
||||
@ -69,9 +86,13 @@ export function createLoader(options) {
|
||||
}
|
||||
|
||||
const file = await process(new VFile({value, path: new URL(context.url)}))
|
||||
// V8 on Erbium.
|
||||
/* c8 ignore next 2 */
|
||||
return {source: String(file).replace(/\/jsx-runtime(?=["'])/g, '$&.js')}
|
||||
let source = String(file)
|
||||
|
||||
if (fixRuntimeWithoutExportMap) {
|
||||
source = String(file).replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
}
|
||||
|
||||
return {source}
|
||||
}
|
||||
/* c8 ignore end */
|
||||
}
|
||||
|
@ -43,13 +43,13 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "npm run build",
|
||||
"build": "rimraf \"lib/**/*.d.ts\" \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage",
|
||||
"test-api": "node --no-warnings --experimental-loader=./index.js ../../node_modules/uvu/bin.js test \"\\.js$\"",
|
||||
"test-api": "node --no-warnings --experimental-loader=./test/react-18-node-loader.js ../../node_modules/uvu/bin.js test \"\\.js$\"",
|
||||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api",
|
||||
"test": "npm run build && npm run test-coverage"
|
||||
},
|
||||
|
8
packages/node-loader/test/react-18-node-loader.js
vendored
Normal file
8
packages/node-loader/test/react-18-node-loader.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import {createLoader} from '../index.js'
|
||||
|
||||
// Load is for Node 17+, the rest for 12, 14, 16.
|
||||
const {load, getFormat, transformSource} = createLoader({
|
||||
fixRuntimeWithoutExportMap: false
|
||||
})
|
||||
|
||||
export {load, getFormat, transformSource}
|
@ -51,8 +51,8 @@
|
||||
"@mdx-js/mdx": "^2.0.0-rc.1",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "npm run build",
|
||||
|
@ -2,7 +2,7 @@ import {test} from 'uvu'
|
||||
import * as assert from 'uvu/assert'
|
||||
import {evaluate} from '@mdx-js/mdx'
|
||||
import React from 'react'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
import * as runtime from 'react/jsx-runtime'
|
||||
import {renderToString} from 'react-dom/server.js'
|
||||
import {MDXProvider, useMDXComponents, withMDXComponents} from '../index.js'
|
||||
|
||||
|
@ -43,8 +43,8 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106"
|
||||
},
|
||||
"scripts": {
|
||||
"#prepack": "npm run build",
|
||||
|
@ -48,8 +48,8 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"react-dom": "^18.0.0-alpha-327d5c484-20211106",
|
||||
"rollup": "^2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -25,10 +25,7 @@ test('@mdx-js/rollup', async () => {
|
||||
|
||||
const output = (await bundle.generate({format: 'es', sourcemap: true})).output
|
||||
|
||||
await fs.writeFile(
|
||||
new URL('./rollup.js', import.meta.url),
|
||||
output[0].code.replace(/\/jsx-runtime(?=["'])/g, '$&.js')
|
||||
)
|
||||
await fs.writeFile(new URL('./rollup.js', import.meta.url), output[0].code)
|
||||
|
||||
const Content = /** @type {MDXContent} */ (
|
||||
/* @ts-expect-error file is dynamically generated */
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {promises as fs} from 'node:fs'
|
||||
import path from 'path'
|
||||
import {promises as fs} from 'node:fs'
|
||||
import {URL, fileURLToPath} from 'node:url'
|
||||
import {transformSync} from 'esbuild'
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
* @typedef {Root|Content} Node
|
||||
*/
|
||||
|
||||
import path from 'path'
|
||||
import process from 'process'
|
||||
import {pathToFileURL} from 'url'
|
||||
import remarkFrontmatter from 'remark-frontmatter'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
@ -35,6 +37,10 @@ import {config} from '../docs/_config.js'
|
||||
|
||||
const own = {}.hasOwnProperty
|
||||
|
||||
const reactUrl = pathToFileURL(
|
||||
path.resolve(process.cwd(), 'node_modules', 'react')
|
||||
)
|
||||
|
||||
const options = {
|
||||
remarkPlugins: [
|
||||
remarkGfm,
|
||||
@ -84,7 +90,8 @@ const options = {
|
||||
rehypePresetMinify,
|
||||
[rehypeMinifyUrl, {ignoreMissingSource: true}]
|
||||
],
|
||||
recmaPlugins: [recmaInjectMeta]
|
||||
recmaPlugins: [recmaInjectMeta],
|
||||
jsxImportSource: reactUrl.href
|
||||
}
|
||||
|
||||
export default options
|
||||
|
Loading…
Reference in New Issue
Block a user