Skip to content

Commit a6acbaa

Browse files
committedSep 18, 2022
minify static object spread in jsx props
1 parent c9b24d8 commit a6acbaa

File tree

2 files changed

+75
-41
lines changed

2 files changed

+75
-41
lines changed
 

‎internal/js_parser/js_parser.go

+53-41
Original file line numberDiff line numberDiff line change
@@ -11870,6 +11870,49 @@ func (p *parser) mangleTemplate(loc logger.Loc, e *js_ast.ETemplate) js_ast.Expr
1187011870
return js_ast.Expr{Loc: loc, Data: e}
1187111871
}
1187211872

11873+
func (p *parser) mangleObjectSpread(properties []js_ast.Property) []js_ast.Property {
11874+
var result []js_ast.Property
11875+
for _, property := range properties {
11876+
if property.Kind == js_ast.PropertySpread {
11877+
switch v := property.ValueOrNil.Data.(type) {
11878+
case *js_ast.EBoolean, *js_ast.ENull, *js_ast.EUndefined, *js_ast.ENumber,
11879+
*js_ast.EBigInt, *js_ast.ERegExp, *js_ast.EFunction, *js_ast.EArrow:
11880+
// This value is ignored because it doesn't have any of its own properties
11881+
continue
11882+
11883+
case *js_ast.EObject:
11884+
for i, p := range v.Properties {
11885+
// Getters are evaluated at iteration time. The property
11886+
// descriptor is not inlined into the caller. Since we are not
11887+
// evaluating code at compile time, just bail if we hit one
11888+
// and preserve the spread with the remaining properties.
11889+
if p.Kind == js_ast.PropertyGet || p.Kind == js_ast.PropertySet {
11890+
v.Properties = v.Properties[i:]
11891+
result = append(result, property)
11892+
break
11893+
}
11894+
11895+
// Also bail if we hit a verbatim "__proto__" key. This will
11896+
// actually set the prototype of the object being spread so
11897+
// inlining it is not correct.
11898+
if p.Kind == js_ast.PropertyNormal && !p.Flags.Has(js_ast.PropertyIsComputed) && !p.Flags.Has(js_ast.PropertyIsMethod) {
11899+
if str, ok := p.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "__proto__") {
11900+
v.Properties = v.Properties[i:]
11901+
result = append(result, property)
11902+
break
11903+
}
11904+
}
11905+
11906+
result = append(result, p)
11907+
}
11908+
continue
11909+
}
11910+
}
11911+
result = append(result, property)
11912+
}
11913+
return result
11914+
}
11915+
1187311916
func containsClosingScriptTag(text string) bool {
1187411917
for {
1187511918
i := strings.Index(text, "</")
@@ -12256,8 +12299,11 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1225612299
}
1225712300

1225812301
// Visit properties
12302+
hasSpread := false
1225912303
for i, property := range e.Properties {
12260-
if property.Kind != js_ast.PropertySpread {
12304+
if property.Kind == js_ast.PropertySpread {
12305+
hasSpread = true
12306+
} else {
1226112307
if mangled, ok := property.Key.Data.(*js_ast.EMangledProp); ok {
1226212308
mangled.Ref = p.symbolForMangledProp(p.loadNameFromRef(mangled.Ref))
1226312309
} else {
@@ -12273,6 +12319,11 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1227312319
e.Properties[i] = property
1227412320
}
1227512321

12322+
// "{a, ...{b, c}, d}" => "{a, b, c, d}"
12323+
if p.options.minifySyntax && hasSpread {
12324+
e.Properties = p.mangleObjectSpread(e.Properties)
12325+
}
12326+
1227612327
// Visit children
1227712328
if len(e.Children) > 0 {
1227812329
for i, child := range e.Children {
@@ -13802,46 +13853,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1380213853
if in.assignTarget == js_ast.AssignTargetNone {
1380313854
// "{a, ...{b, c}, d}" => "{a, b, c, d}"
1380413855
if p.options.minifySyntax && hasSpread {
13805-
var properties []js_ast.Property
13806-
for _, property := range e.Properties {
13807-
if property.Kind == js_ast.PropertySpread {
13808-
switch v := property.ValueOrNil.Data.(type) {
13809-
case *js_ast.EBoolean, *js_ast.ENull, *js_ast.EUndefined, *js_ast.ENumber,
13810-
*js_ast.EBigInt, *js_ast.ERegExp, *js_ast.EFunction, *js_ast.EArrow:
13811-
// This value is ignored because it doesn't have any of its own properties
13812-
continue
13813-
13814-
case *js_ast.EObject:
13815-
for i, p := range v.Properties {
13816-
// Getters are evaluated at iteration time. The property
13817-
// descriptor is not inlined into the caller. Since we are not
13818-
// evaluating code at compile time, just bail if we hit one
13819-
// and preserve the spread with the remaining properties.
13820-
if p.Kind == js_ast.PropertyGet || p.Kind == js_ast.PropertySet {
13821-
v.Properties = v.Properties[i:]
13822-
properties = append(properties, property)
13823-
break
13824-
}
13825-
13826-
// Also bail if we hit a verbatim "__proto__" key. This will
13827-
// actually set the prototype of the object being spread so
13828-
// inlining it is not correct.
13829-
if p.Kind == js_ast.PropertyNormal && !p.Flags.Has(js_ast.PropertyIsComputed) && !p.Flags.Has(js_ast.PropertyIsMethod) {
13830-
if str, ok := p.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "__proto__") {
13831-
v.Properties = v.Properties[i:]
13832-
properties = append(properties, property)
13833-
break
13834-
}
13835-
}
13836-
13837-
properties = append(properties, p)
13838-
}
13839-
continue
13840-
}
13841-
}
13842-
properties = append(properties, property)
13843-
}
13844-
e.Properties = properties
13856+
e.Properties = p.mangleObjectSpread(e.Properties)
1384513857
}
1384613858

1384713859
// Object expressions represent both object literals and binding patterns.

‎internal/js_parser/js_parser_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,16 @@ func expectPrintedJSX(t *testing.T, contents string, expected string) {
156156
})
157157
}
158158

159+
func expectPrintedMangleJSX(t *testing.T, contents string, expected string) {
160+
t.Helper()
161+
expectPrintedCommon(t, contents, expected, config.Options{
162+
MinifySyntax: true,
163+
JSX: config.JSXOptions{
164+
Parse: true,
165+
},
166+
})
167+
}
168+
159169
type JSXAutomaticTestOptions struct {
160170
Development bool
161171
ImportSource string
@@ -3693,6 +3703,18 @@ func TestMangleObject(t *testing.T) {
36933703
expectPrintedMangle(t, "x = {y() {}}?.y()", "x = { y() {\n} }.y();\n")
36943704
}
36953705

3706+
func TestMangleObjectJSX(t *testing.T) {
3707+
expectPrintedJSX(t, "x = <foo bar {...{}} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...{}\n});\n")
3708+
expectPrintedJSX(t, "x = <foo bar {...null} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...null\n});\n")
3709+
expectPrintedJSX(t, "x = <foo bar {...{bar}} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...{ bar }\n});\n")
3710+
expectPrintedJSX(t, "x = <foo bar {...bar} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...bar\n});\n")
3711+
3712+
expectPrintedMangleJSX(t, "x = <foo bar {...{}} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true\n});\n")
3713+
expectPrintedMangleJSX(t, "x = <foo bar {...null} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true\n});\n")
3714+
expectPrintedMangleJSX(t, "x = <foo bar {...{bar}} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n bar\n});\n")
3715+
expectPrintedMangleJSX(t, "x = <foo bar {...bar} />", "x = /* @__PURE__ */ React.createElement(\"foo\", {\n bar: true,\n ...bar\n});\n")
3716+
}
3717+
36963718
func TestMangleArrow(t *testing.T) {
36973719
expectPrintedMangle(t, "var a = () => {}", "var a = () => {\n};\n")
36983720
expectPrintedMangle(t, "var a = () => 123", "var a = () => 123;\n")

0 commit comments

Comments
 (0)
Please sign in to comment.