Optimize jsx spreads of object expressions (#12557)
This commit is contained in:
parent
0d6063f1b9
commit
ed90f17978
@ -316,12 +316,19 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertAttribute(node) {
|
function accumulateAttribute(array, node) {
|
||||||
const value = convertAttributeValue(node.value || t.booleanLiteral(true));
|
|
||||||
|
|
||||||
if (t.isJSXSpreadAttribute(node)) {
|
if (t.isJSXSpreadAttribute(node)) {
|
||||||
return t.spreadElement(node.argument);
|
const arg = node.argument;
|
||||||
|
// Collect properties into props array if spreading object expression
|
||||||
|
if (t.isObjectExpression(arg)) {
|
||||||
|
array.push(...arg.properties);
|
||||||
|
} else {
|
||||||
|
array.push(t.spreadElement(arg));
|
||||||
}
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = convertAttributeValue(node.value || t.booleanLiteral(true));
|
||||||
|
|
||||||
if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
|
if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
|
||||||
value.value = value.value.replace(/\n\s+/g, " ");
|
value.value = value.value.replace(/\n\s+/g, " ");
|
||||||
@ -340,7 +347,8 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
node.name = t.stringLiteral(node.name.name);
|
node.name = t.stringLiteral(node.name.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.inherits(t.objectProperty(node.name, value), node);
|
array.push(t.inherits(t.objectProperty(node.name, value), node));
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildChildrenProperty(children) {
|
function buildChildrenProperty(children) {
|
||||||
@ -420,7 +428,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
// Builds props for React.jsx. This function adds children into the props
|
// Builds props for React.jsx. This function adds children into the props
|
||||||
// and ensures that props is always an object
|
// and ensures that props is always an object
|
||||||
function buildJSXOpeningElementAttributes(attribs, file, children) {
|
function buildJSXOpeningElementAttributes(attribs, file, children) {
|
||||||
const props = attribs.map(convertAttribute);
|
const props = attribs.reduce(accumulateAttribute, []);
|
||||||
|
|
||||||
// In React.jsx, children is no longer a separate argument, but passed in
|
// In React.jsx, children is no longer a separate argument, but passed in
|
||||||
// through the argument object
|
// through the argument object
|
||||||
@ -530,40 +538,38 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
|||||||
found[name] = true;
|
found[name] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
props.push(convertAttribute(attr));
|
accumulateAttribute(props, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
|
return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
|
||||||
}
|
}
|
||||||
|
|
||||||
let props = [];
|
|
||||||
const objs = [];
|
const objs = [];
|
||||||
|
const props = attribs.reduce(accumulateAttribute, []);
|
||||||
|
|
||||||
for (const attr of attribs) {
|
if (!useSpread) {
|
||||||
if (useSpread || !t.isJSXSpreadAttribute(attr)) {
|
// Convert syntax to use multiple objects instead of spread
|
||||||
props.push(convertAttribute(attr));
|
let start = 0;
|
||||||
} else {
|
props.forEach((prop, i) => {
|
||||||
if (props.length) {
|
if (t.isSpreadElement(prop)) {
|
||||||
|
if (i > start) {
|
||||||
|
objs.push(t.objectExpression(props.slice(start, i)));
|
||||||
|
}
|
||||||
|
objs.push(prop.argument);
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (props.length > start) {
|
||||||
|
objs.push(t.objectExpression(props.slice(start)));
|
||||||
|
}
|
||||||
|
} else if (props.length) {
|
||||||
objs.push(t.objectExpression(props));
|
objs.push(t.objectExpression(props));
|
||||||
props = [];
|
|
||||||
}
|
|
||||||
objs.push(attr.argument);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!props.length && !objs.length) {
|
if (!objs.length) {
|
||||||
return t.nullLiteral();
|
return t.nullLiteral();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useSpread) {
|
|
||||||
return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.length) {
|
|
||||||
objs.push(t.objectExpression(props));
|
|
||||||
props = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objs.length === 1) {
|
if (objs.length === 1) {
|
||||||
return objs[0];
|
return objs[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
<p prop prop>text</p>;
|
||||||
|
|
||||||
|
<p {...{prop, prop}}>text</p>;
|
||||||
|
|
||||||
|
<p prop {...{prop}}>text</p>;
|
||||||
|
|
||||||
|
<p {...{prop}} prop>text</p>;
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("p", {
|
||||||
|
prop: true,
|
||||||
|
prop: true,
|
||||||
|
children: "text"
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("p", {
|
||||||
|
prop,
|
||||||
|
prop,
|
||||||
|
children: "text"
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("p", {
|
||||||
|
prop: true,
|
||||||
|
prop,
|
||||||
|
children: "text"
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("p", {
|
||||||
|
prop,
|
||||||
|
prop: true,
|
||||||
|
children: "text"
|
||||||
|
});
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<p {...props}>text</p>;
|
||||||
|
|
||||||
|
<div {...props}>{contents}</div>;
|
||||||
|
|
||||||
|
<img alt="" {...{src, title}} />;
|
||||||
|
|
||||||
|
<blockquote {...{cite}}>{items}</blockquote>;
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { jsx as _jsx } from "react/jsx-runtime";
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("p", { ...props,
|
||||||
|
children: "text"
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("div", { ...props,
|
||||||
|
children: contents
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("img", {
|
||||||
|
alt: "",
|
||||||
|
src,
|
||||||
|
title
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
_jsx("blockquote", {
|
||||||
|
cite,
|
||||||
|
children: items
|
||||||
|
});
|
||||||
11
packages/babel-plugin-transform-react-jsx/test/fixtures/react/avoids-spread/input.js
vendored
Normal file
11
packages/babel-plugin-transform-react-jsx/test/fixtures/react/avoids-spread/input.js
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<E {...props} last />;
|
||||||
|
|
||||||
|
<E first {...props} />;
|
||||||
|
|
||||||
|
<E {...pre} {...suf} />;
|
||||||
|
|
||||||
|
<E first {...pre} mid {...suf} />;
|
||||||
|
|
||||||
|
<E {...pre} mid {...suf} last />;
|
||||||
|
|
||||||
|
<E {...pre} mid1 mid2 {...suf} />;
|
||||||
32
packages/babel-plugin-transform-react-jsx/test/fixtures/react/avoids-spread/output.js
vendored
Normal file
32
packages/babel-plugin-transform-react-jsx/test/fixtures/react/avoids-spread/output.js
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({}, props, {
|
||||||
|
last: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({
|
||||||
|
first: true
|
||||||
|
}, props));
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({}, pre, suf));
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({
|
||||||
|
first: true
|
||||||
|
}, pre, {
|
||||||
|
mid: true
|
||||||
|
}, suf));
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({}, pre, {
|
||||||
|
mid: true
|
||||||
|
}, suf, {
|
||||||
|
last: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement(E, babelHelpers.extends({}, pre, {
|
||||||
|
mid1: true,
|
||||||
|
mid2: true
|
||||||
|
}, suf));
|
||||||
7
packages/babel-plugin-transform-react-jsx/test/fixtures/react/duplicate-props/input.js
vendored
Normal file
7
packages/babel-plugin-transform-react-jsx/test/fixtures/react/duplicate-props/input.js
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<p prop prop>text</p>;
|
||||||
|
|
||||||
|
<p {...{prop, prop}}>text</p>;
|
||||||
|
|
||||||
|
<p prop {...{prop}}>text</p>;
|
||||||
|
|
||||||
|
<p {...{prop}} prop>text</p>;
|
||||||
23
packages/babel-plugin-transform-react-jsx/test/fixtures/react/duplicate-props/output.js
vendored
Normal file
23
packages/babel-plugin-transform-react-jsx/test/fixtures/react/duplicate-props/output.js
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("p", {
|
||||||
|
prop: true,
|
||||||
|
prop: true
|
||||||
|
}, "text");
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("p", {
|
||||||
|
prop,
|
||||||
|
prop
|
||||||
|
}, "text");
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("p", {
|
||||||
|
prop: true,
|
||||||
|
prop
|
||||||
|
}, "text");
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("p", {
|
||||||
|
prop,
|
||||||
|
prop: true
|
||||||
|
}, "text");
|
||||||
7
packages/babel-plugin-transform-react-jsx/test/fixtures/react/flattens-spread/input.js
vendored
Normal file
7
packages/babel-plugin-transform-react-jsx/test/fixtures/react/flattens-spread/input.js
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<p {...props}>text</p>;
|
||||||
|
|
||||||
|
<div {...props}>{contents}</div>;
|
||||||
|
|
||||||
|
<img alt="" {...{src, title}} />;
|
||||||
|
|
||||||
|
<blockquote {...{cite}}>{items}</blockquote>;
|
||||||
17
packages/babel-plugin-transform-react-jsx/test/fixtures/react/flattens-spread/output.js
vendored
Normal file
17
packages/babel-plugin-transform-react-jsx/test/fixtures/react/flattens-spread/output.js
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("p", props, "text");
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("div", props, contents);
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("img", {
|
||||||
|
alt: "",
|
||||||
|
src,
|
||||||
|
title
|
||||||
|
});
|
||||||
|
|
||||||
|
/*#__PURE__*/
|
||||||
|
React.createElement("blockquote", {
|
||||||
|
cite
|
||||||
|
}, items);
|
||||||
Loading…
x
Reference in New Issue
Block a user