Optimize jsx spreads of object expressions (#12557)

This commit is contained in:
Martin Packman 2021-01-05 22:04:26 +00:00 committed by GitHub
parent 0d6063f1b9
commit ed90f17978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 198 additions and 28 deletions

View File

@ -316,13 +316,20 @@ 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,38 +538,36 @@ 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)) {
objs.push(t.objectExpression(props)); if (i > start) {
props = []; objs.push(t.objectExpression(props.slice(start, i)));
}
objs.push(prop.argument);
start = i + 1;
} }
objs.push(attr.argument); });
if (props.length > start) {
objs.push(t.objectExpression(props.slice(start)));
} }
} } else if (props.length) {
if (!props.length && !objs.length) {
return t.nullLiteral();
}
if (useSpread) {
return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
}
if (props.length) {
objs.push(t.objectExpression(props)); objs.push(t.objectExpression(props));
props = []; }
if (!objs.length) {
return t.nullLiteral();
} }
if (objs.length === 1) { if (objs.length === 1) {

View 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>;

View File

@ -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"
});

View File

@ -0,0 +1,7 @@
<p {...props}>text</p>;
<div {...props}>{contents}</div>;
<img alt="" {...{src, title}} />;
<blockquote {...{cite}}>{items}</blockquote>;

View File

@ -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
});

View 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} />;

View 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));

View 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>;

View 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");

View File

@ -0,0 +1,7 @@
<p {...props}>text</p>;
<div {...props}>{contents}</div>;
<img alt="" {...{src, title}} />;
<blockquote {...{cite}}>{items}</blockquote>;

View 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);