From 39524865fbfe54b5584ab35bf09c6b8c0667238e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 20 Jan 2023 13:24:35 -0500 Subject: [PATCH] Reverts "Re-use common JSX element transform for <>..." (#15355) * Reverts "Re-use common JSX element transform for <>..." * add a regression test * fix Babel 8 test error * Update fixtures (Windows) * disable the regression test on Babel 8 Co-authored-by: Babel Bot --- .../inline-elements/fragment/output.js | 2 +- .../fixtures/linux/auto-import-dev/output.mjs | 2 +- .../auto-import-dev-windows/output.mjs | 2 +- .../src/create-plugin.ts | 97 ++++++++++++------- .../output.mjs | 2 +- .../output.mjs | 2 +- .../handle-fragments/output.mjs | 2 +- .../should-allow-nested-fragments/output.mjs | 2 +- .../regression/issue-15353-classic/input.js | 1 + .../issue-15353-classic/options.json | 9 ++ .../regression/issue-15353-classic/output.js | 1 + 11 files changed, 82 insertions(+), 40 deletions(-) create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/input.js create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/options.json create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/output.js diff --git a/packages/babel-plugin-transform-react-inline-elements/test/fixtures/inline-elements/fragment/output.js b/packages/babel-plugin-transform-react-inline-elements/test/fixtures/inline-elements/fragment/output.js index b4a19322bc67..cc24b756f998 100644 --- a/packages/babel-plugin-transform-react-inline-elements/test/fixtures/inline-elements/fragment/output.js +++ b/packages/babel-plugin-transform-react-inline-elements/test/fixtures/inline-elements/fragment/output.js @@ -1 +1 @@ -/*#__PURE__*/babelHelpers.jsx(React.Fragment, {}, void 0, /*#__PURE__*/babelHelpers.jsx("span", {}), /*#__PURE__*/babelHelpers.jsx("div", {})); +/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/babelHelpers.jsx("span", {}), /*#__PURE__*/babelHelpers.jsx("div", {})); diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/output.mjs b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/output.mjs index 9d734c25d566..09c244268112 100644 --- a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/output.mjs +++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/output.mjs @@ -1,7 +1,7 @@ var _jsxFileName = "/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/input.js"; -import { Fragment as _Fragment } from "react/jsx-dev-runtime"; import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime"; import { createElement as _createElement } from "react"; +import { Fragment as _Fragment } from "react/jsx-dev-runtime"; var x = /*#__PURE__*/_jsxDEV(_Fragment, { children: /*#__PURE__*/_jsxDEV("div", { children: [/*#__PURE__*/_jsxDEV("div", {}, "1", false, { diff --git a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/auto-import-dev-windows/output.mjs b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/auto-import-dev-windows/output.mjs index 725b097777e8..d2bc43b24376 100644 --- a/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/auto-import-dev-windows/output.mjs +++ b/packages/babel-plugin-transform-react-jsx-development/test/fixtures/windows/auto-import-dev-windows/output.mjs @@ -1,7 +1,7 @@ var _jsxFileName = "\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\auto-import-dev-windows\\input.js"; -import { Fragment as _Fragment } from "react/jsx-dev-runtime"; import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime"; import { createElement as _createElement } from "react"; +import { Fragment as _Fragment } from "react/jsx-dev-runtime"; var x = /*#__PURE__*/_jsxDEV(_Fragment, { children: /*#__PURE__*/_jsxDEV("div", { children: [/*#__PURE__*/_jsxDEV("div", {}, "1", false, { diff --git a/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts b/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts index 843c8ba2830f..74c0d59ae59e 100644 --- a/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts +++ b/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts @@ -12,6 +12,7 @@ import type { Identifier, JSXAttribute, JSXElement, + JSXFragment, JSXOpeningElement, JSXSpreadAttribute, MemberExpression, @@ -71,6 +72,9 @@ export default function createPlugin({ throwIfNamespace = true, + // TODO (Babel 8): It should throw if this option is used with the automatic runtime + filter, + runtime: RUNTIME_DEFAULT = process.env.BABEL_8_BREAKING ? "automatic" : development @@ -276,24 +280,17 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`, // }, }, - JSXFragment(path, file) { - // <>... -> ... - - const frag = memberExpressionToJSX(get(file, "id/fragment")()); + JSXFragment: { + exit(path, file) { + let callExpr; + if (get(file, "runtime") === "classic") { + callExpr = buildCreateElementFragmentCall(path, file); + } else { + callExpr = buildJSXFragmentCall(path, file); + } - path.replaceWith( - t.inherits( - t.jsxElement( - t.inherits( - t.jsxOpeningElement(frag, []), - path.node.openingFragment, - ), - t.jsxClosingElement(t.cloneNode(frag)), - path.node.children, - ), - path.node, - ), - ); + path.replaceWith(t.inherits(callExpr, path.node)); + }, }, JSXElement: { @@ -603,6 +600,56 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`, return t.objectExpression(props); } + // Builds JSX Fragment <> into + // Production: React.jsx(type, arguments) + // Development: React.jsxDEV(type, { children }) + function buildJSXFragmentCall( + path: NodePath, + file: PluginPass, + ) { + const args = [get(file, "id/fragment")()]; + + const children = t.react.buildChildren(path.node); + + args.push( + t.objectExpression( + children.length > 0 + ? [ + buildChildrenProperty( + //@ts-expect-error The children here contains JSXSpreadChild, + // which will be thrown later + children, + ), + ] + : [], + ), + ); + + if (development) { + args.push( + path.scope.buildUndefinedNode(), + t.booleanLiteral(children.length > 1), + ); + } + + return call(file, children.length > 1 ? "jsxs" : "jsx", args); + } + + // Builds JSX Fragment <> into + // React.createElement(React.Fragment, null, ...children) + function buildCreateElementFragmentCall( + path: NodePath, + file: PluginPass, + ) { + if (filter && !filter(path.node, file)) return; + + return call(file, "createElement", [ + get(file, "id/fragment")(), + t.nullLiteral(), + ...t.react.buildChildren(path.node), + ]); + } + // Builds JSX into: // Production: React.createElement(type, arguments, children) // Development: React.createElement(type, arguments, children, source, self) @@ -806,22 +853,6 @@ function toMemberExpression(id: string): Identifier | MemberExpression { ); } -function memberExpressionToJSX( - expr: t.Node, -): t.JSXMemberExpression | t.JSXIdentifier { - switch (expr.type) { - case "Identifier": - return t.jsxIdentifier(expr.name); - case "MemberExpression": - return t.jsxMemberExpression( - memberExpressionToJSX(expr.object), - memberExpressionToJSX(expr.property) as t.JSXIdentifier, - ); - default: - throw new Error("Internal error: unknown member expression type"); - } -} - function makeSource(path: NodePath, state: PluginPass) { const location = path.node.loc; if (!location) { diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/autoImport/auto-import-react-source-type-module/output.mjs b/packages/babel-plugin-transform-react-jsx/test/fixtures/autoImport/auto-import-react-source-type-module/output.mjs index 5655745123b3..3ce7356a9bea 100644 --- a/packages/babel-plugin-transform-react-jsx/test/fixtures/autoImport/auto-import-react-source-type-module/output.mjs +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/autoImport/auto-import-react-source-type-module/output.mjs @@ -1,7 +1,7 @@ -import { Fragment as _Fragment } from "react/jsx-runtime"; import { jsx as _jsx } from "react/jsx-runtime"; import { createElement as _createElement } from "react"; import { jsxs as _jsxs } from "react/jsx-runtime"; +import { Fragment as _Fragment } from "react/jsx-runtime"; var x = /*#__PURE__*/_jsx(_Fragment, { children: /*#__PURE__*/_jsxs("div", { children: [/*#__PURE__*/_jsx("div", {}, "1"), /*#__PURE__*/_jsx("div", { diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/does-not-add-source-self-automatic/output.mjs b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/does-not-add-source-self-automatic/output.mjs index 5655745123b3..3ce7356a9bea 100644 --- a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/does-not-add-source-self-automatic/output.mjs +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/does-not-add-source-self-automatic/output.mjs @@ -1,7 +1,7 @@ -import { Fragment as _Fragment } from "react/jsx-runtime"; import { jsx as _jsx } from "react/jsx-runtime"; import { createElement as _createElement } from "react"; import { jsxs as _jsxs } from "react/jsx-runtime"; +import { Fragment as _Fragment } from "react/jsx-runtime"; var x = /*#__PURE__*/_jsx(_Fragment, { children: /*#__PURE__*/_jsxs("div", { children: [/*#__PURE__*/_jsx("div", {}, "1"), /*#__PURE__*/_jsx("div", { diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/handle-fragments/output.mjs b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/handle-fragments/output.mjs index 1f4bd7b1e46a..12b47c76828a 100644 --- a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/handle-fragments/output.mjs +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/handle-fragments/output.mjs @@ -1,5 +1,5 @@ -import { Fragment as _Fragment } from "react/jsx-runtime"; import { jsx as _jsx } from "react/jsx-runtime"; +import { Fragment as _Fragment } from "react/jsx-runtime"; var x = /*#__PURE__*/_jsx(_Fragment, { children: /*#__PURE__*/_jsx("div", {}) }); diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/should-allow-nested-fragments/output.mjs b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/should-allow-nested-fragments/output.mjs index 5fc7b761b670..8f5ce8c7a4d9 100644 --- a/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/should-allow-nested-fragments/output.mjs +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/react-automatic/should-allow-nested-fragments/output.mjs @@ -1,5 +1,5 @@ -import { Fragment as _Fragment } from "react/jsx-runtime"; import { jsx as _jsx } from "react/jsx-runtime"; +import { Fragment as _Fragment } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; /*#__PURE__*/_jsx("div", { children: /*#__PURE__*/_jsxs(_Fragment, { diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/input.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/input.js new file mode 100644 index 000000000000..2757cd461332 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/input.js @@ -0,0 +1 @@ +<>Test; diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/options.json b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/options.json new file mode 100644 index 000000000000..f6fefb0c3b61 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/options.json @@ -0,0 +1,9 @@ +{ + "BABEL_8_BREAKING": false, + "plugins": [ + [ + "transform-react-jsx", + { "pragma": "m", "pragmaFrag": "'['", "runtime": "classic" } + ] + ] +} diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/output.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/output.js new file mode 100644 index 000000000000..37323fce8d38 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/regression/issue-15353-classic/output.js @@ -0,0 +1 @@ +m('[', null, "Test");