Skip to content

Commit

Permalink
Optimize jsx spreads of object expressions (#12557)
Browse files Browse the repository at this point in the history
  • Loading branch information
bz2 committed Jan 5, 2021
1 parent 0d6063f commit ed90f17
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 27 deletions.
60 changes: 33 additions & 27 deletions packages/babel-plugin-transform-react-jsx/src/create-plugin.js
Expand Up @@ -316,13 +316,20 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
}
}

function convertAttribute(node) {
const value = convertAttributeValue(node.value || t.booleanLiteral(true));

function accumulateAttribute(array, 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)) {
value.value = value.value.replace(/\n\s+/g, " ");

Expand All @@ -340,7 +347,8 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
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) {
Expand Down Expand Up @@ -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
// and ensures that props is always an object
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
// through the argument object
Expand Down Expand Up @@ -530,40 +538,38 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
found[name] = true;
}

props.push(convertAttribute(attr));
accumulateAttribute(props, attr);
}

return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
}

let props = [];
const objs = [];

for (const attr of attribs) {
if (useSpread || !t.isJSXSpreadAttribute(attr)) {
props.push(convertAttribute(attr));
} else {
if (props.length) {
objs.push(t.objectExpression(props));
props = [];
const props = attribs.reduce(accumulateAttribute, []);

if (!useSpread) {
// Convert syntax to use multiple objects instead of spread
let start = 0;
props.forEach((prop, i) => {
if (t.isSpreadElement(prop)) {
if (i > start) {
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) {
objs.push(t.objectExpression(props));
}

if (!props.length && !objs.length) {
if (!objs.length) {
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) {
return objs[0];
}
Expand Down
@@ -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
});
@@ -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} />;
@@ -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));
@@ -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,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");
@@ -0,0 +1,7 @@
<p {...props}>text</p>;

<div {...props}>{contents}</div>;

<img alt="" {...{src, title}} />;

<blockquote {...{cite}}>{items}</blockquote>;
@@ -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);

0 comments on commit ed90f17

Please sign in to comment.