Lazily inject imports to the JSX runtime (#12493)
This commit is contained in:
parent
a0c1a9a9e4
commit
28d2cbcbf3
@ -43,11 +43,6 @@ export function helper(babel, options) {
|
||||
const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
|
||||
const JSX_FRAG_ANNOTATION_REGEX = /\*?\s*@jsxFrag\s+([^\s]+)/;
|
||||
|
||||
// This is the number of possible import names
|
||||
// development: jsxDEV, Fragment, createElement
|
||||
// production: jsx, jsxs, Fragment, createElement
|
||||
const IMPORT_NAME_SIZE = options.development ? 3 : 4;
|
||||
|
||||
const {
|
||||
importSource: IMPORT_SOURCE_DEFAULT = DEFAULT.importSource,
|
||||
runtime: RUNTIME_DEFAULT = DEFAULT.runtime,
|
||||
@ -214,44 +209,33 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
);
|
||||
}
|
||||
|
||||
const importName = addAutoImports(path, {
|
||||
...state.opts,
|
||||
source,
|
||||
});
|
||||
|
||||
state.set(
|
||||
"@babel/plugin-react-jsx/jsxIdentifier",
|
||||
createIdentifierParser(
|
||||
createIdentifierName(
|
||||
createImportLazily(
|
||||
state,
|
||||
path,
|
||||
options.development ? "jsxDEV" : "jsx",
|
||||
importName,
|
||||
),
|
||||
source,
|
||||
),
|
||||
);
|
||||
state.set(
|
||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
||||
createIdentifierParser(
|
||||
createIdentifierName(
|
||||
createImportLazily(
|
||||
state,
|
||||
path,
|
||||
options.development ? "jsxDEV" : "jsxs",
|
||||
importName,
|
||||
),
|
||||
source,
|
||||
),
|
||||
);
|
||||
|
||||
state.set(
|
||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
||||
createIdentifierParser(
|
||||
createIdentifierName(path, "createElement", importName),
|
||||
),
|
||||
createImportLazily(state, path, "createElement", source),
|
||||
);
|
||||
|
||||
state.set(
|
||||
"@babel/plugin-react-jsx/jsxFragIdentifier",
|
||||
createIdentifierParser(
|
||||
createIdentifierName(path, "Fragment", importName),
|
||||
),
|
||||
createImportLazily(state, path, "Fragment", source),
|
||||
);
|
||||
|
||||
state.set(
|
||||
@ -313,44 +297,6 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
return false;
|
||||
}
|
||||
|
||||
function createIdentifierName(path, name, importName) {
|
||||
if (isModule(path)) {
|
||||
const identifierName = `${importName[name]}`;
|
||||
return identifierName;
|
||||
} else {
|
||||
return `${importName[name]}.${name}`;
|
||||
}
|
||||
}
|
||||
|
||||
function getImportNames(parentPath) {
|
||||
const imports = new Set();
|
||||
|
||||
parentPath.traverse({
|
||||
"JSXElement|JSXFragment"(path) {
|
||||
if (path.type === "JSXFragment") imports.add("Fragment");
|
||||
const openingPath = path.get("openingElement");
|
||||
|
||||
const validChildren = t.react.buildChildren(openingPath.parent);
|
||||
let importName;
|
||||
if (path.type === "JSXElement" && shouldUseCreateElement(path)) {
|
||||
importName = "createElement";
|
||||
} else if (options.development) {
|
||||
importName = "jsxDEV";
|
||||
} else if (validChildren.length > 1) {
|
||||
importName = "jsxs";
|
||||
} else {
|
||||
importName = "jsx";
|
||||
}
|
||||
imports.add(importName);
|
||||
|
||||
if (imports.size === IMPORT_NAME_SIZE) {
|
||||
path.stop();
|
||||
}
|
||||
},
|
||||
});
|
||||
return imports;
|
||||
}
|
||||
|
||||
function getSource(source, importName) {
|
||||
switch (importName) {
|
||||
case "Fragment":
|
||||
@ -367,47 +313,40 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
}
|
||||
}
|
||||
|
||||
function addAutoImports(path, state) {
|
||||
const imports = getImportNames(path, state);
|
||||
function createImportLazily(pass, path, importName, source) {
|
||||
return () => {
|
||||
const actualSource = getSource(source, importName);
|
||||
if (isModule(path)) {
|
||||
// import {jsx} from "react";
|
||||
// import {createElement} from "react";
|
||||
const importMap = {};
|
||||
let reference = pass.get(
|
||||
`@babel/plugin-react-jsx/imports/${importName}`,
|
||||
);
|
||||
if (reference) return t.cloneNode(reference);
|
||||
|
||||
imports.forEach(importName => {
|
||||
if (!importMap[importName]) {
|
||||
importMap[importName] = addNamed(
|
||||
path,
|
||||
importName,
|
||||
getSource(state.source, importName),
|
||||
{
|
||||
reference = addNamed(path, importName, actualSource, {
|
||||
importedInterop: "uncompiled",
|
||||
ensureLiveReference: true,
|
||||
},
|
||||
).name;
|
||||
}
|
||||
});
|
||||
pass.set(`@babel/plugin-react-jsx/imports/${importName}`, reference);
|
||||
|
||||
return importMap;
|
||||
return reference;
|
||||
} else {
|
||||
const importMap = {};
|
||||
const sourceMap = {};
|
||||
imports.forEach(importName => {
|
||||
const source = getSource(state.source, importName);
|
||||
if (!importMap[importName]) {
|
||||
if (!sourceMap[source]) {
|
||||
// var _react = require("react")
|
||||
sourceMap[source] = addNamespace(path, source, {
|
||||
let reference = pass.get(
|
||||
`@babel/plugin-react-jsx/requires/${actualSource}`,
|
||||
);
|
||||
if (reference) {
|
||||
reference = t.cloneNode(reference);
|
||||
} else {
|
||||
reference = addNamespace(path, actualSource, {
|
||||
importedInterop: "uncompiled",
|
||||
ensureLiveReference: true,
|
||||
}).name;
|
||||
});
|
||||
pass.set(
|
||||
`@babel/plugin-react-jsx/requires/${actualSource}`,
|
||||
reference,
|
||||
);
|
||||
}
|
||||
|
||||
importMap[importName] = sourceMap[source];
|
||||
}
|
||||
});
|
||||
return importMap;
|
||||
return t.memberExpression(reference, t.identifier(importName));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createIdentifierParser(id) {
|
||||
|
||||
@ -26,13 +26,20 @@ export default declare((api, options) => {
|
||||
state.pure =
|
||||
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
||||
} else {
|
||||
state.jsxCallee = pass.get("@babel/plugin-react-jsx/jsxIdentifier")();
|
||||
state.jsxStaticCallee = pass.get(
|
||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
||||
)();
|
||||
state.createElementCallee = pass.get(
|
||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
||||
)();
|
||||
const getter = get => ({ enumerable: true, configurable: true, get });
|
||||
|
||||
// TODO(Babel 8): helper-builder-react-jsx expects those properties to be AST nodes, but we want to
|
||||
// generate them lazily so that we only inject imports when needed.
|
||||
// These should actually be functions.
|
||||
Object.defineProperties(state, {
|
||||
jsxCallee: getter(pass.get("@babel/plugin-react-jsx/jsxIdentifier")),
|
||||
jsxStaticCallee: getter(
|
||||
pass.get("@babel/plugin-react-jsx/jsxStaticIdentifier"),
|
||||
),
|
||||
createElementCallee: getter(
|
||||
pass.get("@babel/plugin-react-jsx/createElementIdentifier"),
|
||||
),
|
||||
});
|
||||
|
||||
state.pure =
|
||||
PURE_ANNOTATION ??
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Fragment as _Fragment } from "react/jsx-dev-runtime";
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
||||
import { Fragment as _Fragment } from "react/jsx-dev-runtime";
|
||||
var _jsxFileName = "<CWD>/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/input.js";
|
||||
|
||||
var x = /*#__PURE__*/_jsxDEV(_Fragment, {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Fragment as _Fragment } from "react/jsx-dev-runtime";
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
||||
import { Fragment as _Fragment } from "react/jsx-dev-runtime";
|
||||
var _jsxFileName = "<CWD>\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\auto-import-dev-windows\\input.js";
|
||||
|
||||
var x = /*#__PURE__*/_jsxDEV(_Fragment, {
|
||||
|
||||
@ -27,13 +27,20 @@ export default declare((api, options) => {
|
||||
state.pure =
|
||||
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
||||
} else {
|
||||
state.jsxCallee = pass.get("@babel/plugin-react-jsx/jsxIdentifier")();
|
||||
state.jsxStaticCallee = pass.get(
|
||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
||||
)();
|
||||
state.createElementCallee = pass.get(
|
||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
||||
)();
|
||||
const getter = get => ({ enumerable: true, configurable: true, get });
|
||||
|
||||
// TODO(Babel 8): helper-builder-react-jsx expects those properties to be AST nodes, but we want to
|
||||
// generate them lazily so that we only inject imports when needed.
|
||||
// These should actually be functions.
|
||||
Object.defineProperties(state, {
|
||||
jsxCallee: getter(pass.get("@babel/plugin-react-jsx/jsxIdentifier")),
|
||||
jsxStaticCallee: getter(
|
||||
pass.get("@babel/plugin-react-jsx/jsxStaticIdentifier"),
|
||||
),
|
||||
createElementCallee: getter(
|
||||
pass.get("@babel/plugin-react-jsx/createElementIdentifier"),
|
||||
),
|
||||
});
|
||||
|
||||
state.pure =
|
||||
PURE_ANNOTATION ??
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsxs as _jsxs } 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";
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||
children: /*#__PURE__*/_jsxs("div", {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import * as react from "react";
|
||||
var y = react.createElement("div", {
|
||||
foo: 1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsxs("div", {
|
||||
children: ["foo", "bar", "baz", /*#__PURE__*/_jsx("div", {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsxs as _jsxs } 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";
|
||||
import { createElement as _createElement } from "react";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||
children: /*#__PURE__*/_jsxs("div", {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||
children: /*#__PURE__*/_jsx("div", {})
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsxs("div", {
|
||||
children: [/*#__PURE__*/_jsx("span", {}), [/*#__PURE__*/_jsx("span", {}, '0'), /*#__PURE__*/_jsx("span", {}, '1')]]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsxs("div", {
|
||||
children: [/*#__PURE__*/_jsx("div", {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
var x = /*#__PURE__*/_jsxs("div", {
|
||||
children: [/*#__PURE__*/_jsx("div", {}, "1"), /*#__PURE__*/_jsx("div", {
|
||||
|
||||
@ -1 +1,3 @@
|
||||
const foo = /*#__PURE__*/undefined.jsx("p", {});
|
||||
var _reactJsxRuntime = require("react/jsx-runtime");
|
||||
|
||||
const foo = /*#__PURE__*/_reactJsxRuntime.jsx("p", {});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user