Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support jsx dev runtime #2045

Merged
merged 5 commits into from Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/mdx/lib/core.js
Expand Up @@ -125,7 +125,7 @@ export function createProcessor(options = {}) {
.use(recmaJsxRewrite, {development, providerImportSource, outputFormat})

if (!jsx) {
pipeline.use(recmaJsxBuild, {outputFormat})
pipeline.use(recmaJsxBuild, {development, outputFormat})
}

pipeline.use(recmaStringify, {SourceMapGenerator}).use(recmaPlugins || [])
Expand Down
9 changes: 5 additions & 4 deletions packages/mdx/lib/plugin/recma-jsx-build.js
@@ -1,5 +1,6 @@
/**
* @typedef {import('estree-jsx').Program} Program
* @typedef {import('estree-util-build-jsx').BuildJsxOptions} BuildJsxOptions
*
* @typedef RecmaJsxBuildOptions
* @property {'program'|'function-body'} [outputFormat='program']
Expand All @@ -15,13 +16,13 @@ import {toIdOrMemberExpression} from '../util/estree-util-to-id-or-member-expres
* A plugin to build JSX into function calls.
* `estree-util-build-jsx` does all the work for us!
*
* @type {import('unified').Plugin<[RecmaJsxBuildOptions]|[], Program>}
* @type {import('unified').Plugin<[BuildJsxOptions & RecmaJsxBuildOptions?], Program>}
*/
export function recmaJsxBuild(options = {}) {
const {outputFormat} = options
const {development, outputFormat} = options

return (tree) => {
buildJsx(tree)
return (tree, file) => {
buildJsx(tree, {development, filePath: file.history[0]})

// When compiling to a function body, replace the import that was just
// generated, and get `jsx`, `jsxs`, and `Fragment` from `arguments[0]`
Expand Down
50 changes: 50 additions & 0 deletions packages/mdx/test/compile.js
Expand Up @@ -548,6 +548,56 @@ test('compile', async () => {
)
console.log('\nnote: the preceding warning is expected!\n')

const developmentSourceNode = (
await run(
compileSync(
{value: '<div />', path: 'path/to/file.js'},
{development: true}
).value
)
)({})
assert.equal(
// @ts-expect-error React attaches source information on this property,
// but it’s private and untyped.
developmentSourceNode._source,
{fileName: 'path/to/file.js', lineNumber: 1, columnNumber: 1},
'should expose source information in the automatic jsx dev runtime'
)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test above uses an undocumented private property of React elements. The test below asserts the generated source code. None of these tests is ideal, but I’m not sure which is worse. I suggest to keep only one of them though.


assert.equal(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe good to move this one next to the jsx tests (L826), in a new test for automatic runtime output?
Sometimes the output changes a bit and then its easier if all the output tests are next to eachother?

compileSync({value: '<X />', path: 'path/to/file.js'}, {development: true})
.value,
[
'/*@jsxRuntime automatic @jsxImportSource react*/',
'import {jsxDEV as _jsxDEV} from "react/jsx-dev-runtime";',
'function MDXContent(props = {}) {',
' const {wrapper: MDXLayout} = props.components || ({});',
' return MDXLayout ? _jsxDEV(MDXLayout, Object.assign({}, props, {',
' children: _jsxDEV(_createMdxContent, {}, undefined, false, {',
' fileName: "path/to/file.js"',
' }, this)',
' }), undefined, false, {',
' fileName: "path/to/file.js"',
' }, this) : _createMdxContent();',
' function _createMdxContent() {',
' const {X} = props.components || ({});',
' if (!X) _missingMdxReference("X", true, "1:1-1:6");',
' return _jsxDEV(X, {}, undefined, false, {',
' fileName: "path/to/file.js",',
' lineNumber: 1,',
' columnNumber: 1',
' }, this);',
' }',
'}',
'export default MDXContent;',
'function _missingMdxReference(id, component, place) {',
' throw new Error("Expected " + (component ? "component" : "object") + " `" + id + "` to be defined: you likely forgot to import, pass, or provide it." + (place ? "\\nIt’s referenced in your code at `" + place + "` in `path/to/file.js`" : ""));',
'}',
''
].join('\n'),
'should support the jsx dev runtime'
)

try {
renderToStaticMarkup(
React.createElement(await run(compileSync('<X />', {development: true})))
Expand Down