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_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/;
|
||||||
const JSX_FRAG_ANNOTATION_REGEX = /\*?\s*@jsxFrag\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 {
|
const {
|
||||||
importSource: IMPORT_SOURCE_DEFAULT = DEFAULT.importSource,
|
importSource: IMPORT_SOURCE_DEFAULT = DEFAULT.importSource,
|
||||||
runtime: RUNTIME_DEFAULT = DEFAULT.runtime,
|
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(
|
state.set(
|
||||||
"@babel/plugin-react-jsx/jsxIdentifier",
|
"@babel/plugin-react-jsx/jsxIdentifier",
|
||||||
createIdentifierParser(
|
createImportLazily(
|
||||||
createIdentifierName(
|
state,
|
||||||
path,
|
path,
|
||||||
options.development ? "jsxDEV" : "jsx",
|
options.development ? "jsxDEV" : "jsx",
|
||||||
importName,
|
source,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
state.set(
|
state.set(
|
||||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
||||||
createIdentifierParser(
|
createImportLazily(
|
||||||
createIdentifierName(
|
state,
|
||||||
path,
|
path,
|
||||||
options.development ? "jsxDEV" : "jsxs",
|
options.development ? "jsxDEV" : "jsxs",
|
||||||
importName,
|
source,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
state.set(
|
state.set(
|
||||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
"@babel/plugin-react-jsx/createElementIdentifier",
|
||||||
createIdentifierParser(
|
createImportLazily(state, path, "createElement", source),
|
||||||
createIdentifierName(path, "createElement", importName),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
state.set(
|
state.set(
|
||||||
"@babel/plugin-react-jsx/jsxFragIdentifier",
|
"@babel/plugin-react-jsx/jsxFragIdentifier",
|
||||||
createIdentifierParser(
|
createImportLazily(state, path, "Fragment", source),
|
||||||
createIdentifierName(path, "Fragment", importName),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
state.set(
|
state.set(
|
||||||
@ -313,44 +297,6 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
return false;
|
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) {
|
function getSource(source, importName) {
|
||||||
switch (importName) {
|
switch (importName) {
|
||||||
case "Fragment":
|
case "Fragment":
|
||||||
@ -367,47 +313,40 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAutoImports(path, state) {
|
function createImportLazily(pass, path, importName, source) {
|
||||||
const imports = getImportNames(path, state);
|
return () => {
|
||||||
|
const actualSource = getSource(source, importName);
|
||||||
if (isModule(path)) {
|
if (isModule(path)) {
|
||||||
// import {jsx} from "react";
|
let reference = pass.get(
|
||||||
// import {createElement} from "react";
|
`@babel/plugin-react-jsx/imports/${importName}`,
|
||||||
const importMap = {};
|
);
|
||||||
|
if (reference) return t.cloneNode(reference);
|
||||||
|
|
||||||
imports.forEach(importName => {
|
reference = addNamed(path, importName, actualSource, {
|
||||||
if (!importMap[importName]) {
|
|
||||||
importMap[importName] = addNamed(
|
|
||||||
path,
|
|
||||||
importName,
|
|
||||||
getSource(state.source, importName),
|
|
||||||
{
|
|
||||||
importedInterop: "uncompiled",
|
importedInterop: "uncompiled",
|
||||||
ensureLiveReference: true,
|
|
||||||
},
|
|
||||||
).name;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
pass.set(`@babel/plugin-react-jsx/imports/${importName}`, reference);
|
||||||
|
|
||||||
return importMap;
|
return reference;
|
||||||
} else {
|
} else {
|
||||||
const importMap = {};
|
let reference = pass.get(
|
||||||
const sourceMap = {};
|
`@babel/plugin-react-jsx/requires/${actualSource}`,
|
||||||
imports.forEach(importName => {
|
);
|
||||||
const source = getSource(state.source, importName);
|
if (reference) {
|
||||||
if (!importMap[importName]) {
|
reference = t.cloneNode(reference);
|
||||||
if (!sourceMap[source]) {
|
} else {
|
||||||
// var _react = require("react")
|
reference = addNamespace(path, actualSource, {
|
||||||
sourceMap[source] = addNamespace(path, source, {
|
|
||||||
importedInterop: "uncompiled",
|
importedInterop: "uncompiled",
|
||||||
ensureLiveReference: true,
|
});
|
||||||
}).name;
|
pass.set(
|
||||||
|
`@babel/plugin-react-jsx/requires/${actualSource}`,
|
||||||
|
reference,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
importMap[importName] = sourceMap[source];
|
return t.memberExpression(reference, t.identifier(importName));
|
||||||
}
|
|
||||||
});
|
|
||||||
return importMap;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createIdentifierParser(id) {
|
function createIdentifierParser(id) {
|
||||||
|
|||||||
@ -26,13 +26,20 @@ export default declare((api, options) => {
|
|||||||
state.pure =
|
state.pure =
|
||||||
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
||||||
} else {
|
} else {
|
||||||
state.jsxCallee = pass.get("@babel/plugin-react-jsx/jsxIdentifier")();
|
const getter = get => ({ enumerable: true, configurable: true, get });
|
||||||
state.jsxStaticCallee = pass.get(
|
|
||||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
// 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.
|
||||||
state.createElementCallee = pass.get(
|
// These should actually be functions.
|
||||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
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 =
|
state.pure =
|
||||||
PURE_ANNOTATION ??
|
PURE_ANNOTATION ??
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
import { Fragment as _Fragment } from "react/jsx-dev-runtime";
|
||||||
import { createElement as _createElement } from "react";
|
import { createElement as _createElement } from "react";
|
||||||
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
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 _jsxFileName = "<CWD>/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/auto-import-dev/input.js";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsxDEV(_Fragment, {
|
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 { createElement as _createElement } from "react";
|
||||||
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
|
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 _jsxFileName = "<CWD>\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\auto-import-dev-windows\\input.js";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsxDEV(_Fragment, {
|
var x = /*#__PURE__*/_jsxDEV(_Fragment, {
|
||||||
|
|||||||
@ -27,13 +27,20 @@ export default declare((api, options) => {
|
|||||||
state.pure =
|
state.pure =
|
||||||
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
PURE_ANNOTATION ?? !pass.get("@babel/plugin-react-jsx/pragmaSet");
|
||||||
} else {
|
} else {
|
||||||
state.jsxCallee = pass.get("@babel/plugin-react-jsx/jsxIdentifier")();
|
const getter = get => ({ enumerable: true, configurable: true, get });
|
||||||
state.jsxStaticCallee = pass.get(
|
|
||||||
"@babel/plugin-react-jsx/jsxStaticIdentifier",
|
// 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.
|
||||||
state.createElementCallee = pass.get(
|
// These should actually be functions.
|
||||||
"@babel/plugin-react-jsx/createElementIdentifier",
|
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 =
|
state.pure =
|
||||||
PURE_ANNOTATION ??
|
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 { 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, {
|
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||||
children: /*#__PURE__*/_jsxs("div", {
|
children: /*#__PURE__*/_jsxs("div", {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||||
import { createElement as _createElement } from "react";
|
import { createElement as _createElement } from "react";
|
||||||
import { jsx as _jsx } from "react/jsx-runtime";
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
||||||
import * as react from "react";
|
import * as react from "react";
|
||||||
var y = react.createElement("div", {
|
var y = react.createElement("div", {
|
||||||
foo: 1
|
foo: 1
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { jsx as _jsx } from "react/jsx-runtime";
|
|
||||||
import { jsxs as _jsxs } 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", {
|
var x = /*#__PURE__*/_jsxs("div", {
|
||||||
children: ["foo", "bar", "baz", /*#__PURE__*/_jsx("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 { 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, {
|
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||||
children: /*#__PURE__*/_jsxs("div", {
|
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 { Fragment as _Fragment } from "react/jsx-runtime";
|
||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsx(_Fragment, {
|
var x = /*#__PURE__*/_jsx(_Fragment, {
|
||||||
children: /*#__PURE__*/_jsx("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 { jsxs as _jsxs } from "react/jsx-runtime";
|
||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsxs("div", {
|
var x = /*#__PURE__*/_jsxs("div", {
|
||||||
children: [/*#__PURE__*/_jsx("span", {}), [/*#__PURE__*/_jsx("span", {}, '0'), /*#__PURE__*/_jsx("span", {}, '1')]]
|
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 { jsxs as _jsxs } from "react/jsx-runtime";
|
||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsxs("div", {
|
var x = /*#__PURE__*/_jsxs("div", {
|
||||||
children: [/*#__PURE__*/_jsx("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 { jsxs as _jsxs } from "react/jsx-runtime";
|
||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
var x = /*#__PURE__*/_jsxs("div", {
|
var x = /*#__PURE__*/_jsxs("div", {
|
||||||
children: [/*#__PURE__*/_jsx("div", {}, "1"), /*#__PURE__*/_jsx("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