Skip to content

Commit f759693

Browse files
committed
css: fix ordering with @layer before @import
1 parent c73f0f8 commit f759693

File tree

5 files changed

+487
-269
lines changed

5 files changed

+487
-269
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@
66

77
Previously esbuild's generated names for local names in CSS were only unique within a given entry point (or across all entry points when code splitting was enabled). That meant that building multiple entry points with esbuild could result in local names being renamed to the same identifier even when those entry points were built simultaneously within a single esbuild API call. This problem was especially likely to happen with minification enabled. With this release, esbuild will now avoid renaming local names from two separate entry points to the same name if those entry points were built with a single esbuild API call, even when code splitting is disabled.
88

9+
* Fix CSS ordering bug with `@layer` before `@import`
10+
11+
CSS lets you put `@layer` rules before `@import` rules to define the order of layers in a stylesheet. Previously esbuild's CSS bundler incorrectly ordered these after the imported files because before the introduction of cascade layers to CSS, imported files could be bundled by removing the `@import` rules and then joining files together in the right order. But with `@layer`, CSS files may now need to be split apart into multiple pieces in the bundle. For example:
12+
13+
```
14+
/* Original code */
15+
@layer start;
16+
@import "data:text/css,@layer inner.start;";
17+
@import "data:text/css,@layer inner.end;";
18+
@layer end;
19+
20+
/* Old output (with --bundle) */
21+
@layer inner.start;
22+
@layer inner.end;
23+
@layer start;
24+
@layer end;
25+
26+
/* New output (with --bundle) */
27+
@layer start;
28+
@layer inner.start;
29+
@layer inner.end;
30+
@layer end;
31+
```
32+
933
* Unwrap nested duplicate `@media` rules ([#3226](https://github.com/evanw/esbuild/issues/3226))
1034
1135
With this release, esbuild's CSS minifier will now automatically unwrap duplicate nested `@media` rules:

internal/bundler_tests/bundler_css_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2491,3 +2491,49 @@ url-token-whitespace-eof.css: WARNING: Expected ";" but found end of file
24912491
`,
24922492
})
24932493
}
2494+
2495+
func TestCSSAtLayerBeforeImportNoBundle(t *testing.T) {
2496+
css_suite.expectBundled(t, bundled{
2497+
files: map[string]string{
2498+
"/entry.css": `
2499+
@layer layer1, layer2.layer3;
2500+
@import "a.css";
2501+
@import "b.css";
2502+
@layer layer6.layer7, layer8;
2503+
`,
2504+
},
2505+
entryPaths: []string{"/entry.css"},
2506+
options: config.Options{
2507+
Mode: config.ModePassThrough,
2508+
AbsOutputDir: "/out",
2509+
},
2510+
})
2511+
}
2512+
2513+
func TestCSSAtLayerBeforeImportBundle(t *testing.T) {
2514+
css_suite.expectBundled(t, bundled{
2515+
files: map[string]string{
2516+
"/entry.css": `
2517+
@layer layer1, layer2.layer3;
2518+
@import "a.css";
2519+
@import "b.css";
2520+
@layer layer6.layer7, layer8;
2521+
`,
2522+
"/a.css": `
2523+
@layer layer4 {
2524+
a { color: red }
2525+
}
2526+
`,
2527+
"/b.css": `
2528+
@layer layer5 {
2529+
b { color: red }
2530+
}
2531+
`,
2532+
},
2533+
entryPaths: []string{"/entry.css"},
2534+
options: config.Options{
2535+
Mode: config.ModeBundle,
2536+
AbsOutputDir: "/out",
2537+
},
2538+
})
2539+
}

internal/bundler_tests/snapshots/snapshots_css.txt

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ TestCSSAtImport
8989
================================================================================
9090
TestCSSAtImportConditionsAtLayerBundle
9191
---------- /out/case1.css ----------
92-
/* case1-foo.css */
9392
@layer first.one;
9493

9594
/* case1-foo.css */
@@ -109,7 +108,6 @@ TestCSSAtImportConditionsAtLayerBundle
109108
/* case1.css */
110109

111110
---------- /out/case2.css ----------
112-
/* case2-foo.css */
113111
@layer first.one;
114112

115113
/* case2-bar.css */
@@ -146,7 +144,6 @@ TestCSSAtImportConditionsAtLayerBundle
146144
/* case3.css */
147145

148146
---------- /out/case4.css ----------
149-
/* case4-foo.css */
150147
@layer first {
151148
@layer one, one.two, one.three.four;
152149
}
@@ -197,7 +194,6 @@ TestCSSAtImportConditionsAtLayerBundle
197194
/* case5.css */
198195

199196
---------- /out/case6.css ----------
200-
/* case6-foo.css */
201197
@layer first;
202198

203199
/* case6-foo.css */
@@ -235,7 +231,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile
235231
/* case1.css */
236232

237233
---------- /out/case2.css ----------
238-
/* a.css */
239234
@layer first;
240235

241236
/* b.css */
@@ -255,10 +250,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile
255250
/* case2.css */
256251

257252
---------- /out/case3.css ----------
258-
/* a.css */
259253
@layer first;
260-
261-
/* b.css */
262254
@layer last;
263255

264256
/* a.css */
@@ -278,7 +270,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile
278270
/* case3.css */
279271

280272
---------- /out/case4.css ----------
281-
/* a.css */
282273
@layer first;
283274

284275
/* b.css */
@@ -298,10 +289,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile
298289
/* case4.css */
299290

300291
---------- /out/case5.css ----------
301-
/* a.css */
302292
@layer first;
303-
304-
/* b.css */
305293
@layer last;
306294

307295
/* a.css */
@@ -321,7 +309,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile
321309
/* case5.css */
322310

323311
---------- /out/case6.css ----------
324-
/* a.css */
325312
@layer first;
326313

327314
/* b.css */
@@ -353,7 +340,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerOnImport
353340
/* case1.css */
354341

355342
---------- /out/case2.css ----------
356-
/* a.css */
357343
@layer first;
358344

359345
/* b.css */
@@ -373,10 +359,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerOnImport
373359
/* case2.css */
374360

375361
---------- /out/case3.css ----------
376-
/* a.css */
377362
@layer first;
378-
379-
/* b.css */
380363
@layer last;
381364

382365
/* a.css */
@@ -396,7 +379,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerOnImport
396379
/* case3.css */
397380

398381
---------- /out/case4.css ----------
399-
/* a.css */
400382
@layer first;
401383

402384
/* b.css */
@@ -416,10 +398,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerOnImport
416398
/* case4.css */
417399

418400
---------- /out/case5.css ----------
419-
/* a.css */
420401
@layer first;
421-
422-
/* b.css */
423402
@layer last;
424403

425404
/* a.css */
@@ -439,7 +418,6 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerOnImport
439418
/* case5.css */
440419

441420
---------- /out/case6.css ----------
442-
/* a.css */
443421
@layer first;
444422

445423
/* b.css */
@@ -734,7 +712,6 @@ TestCSSAtImportConditionsFromExternalRepo
734712
/* at-keyframes/001/style.css */
735713

736714
---------- /out/at-layer/001/style.css ----------
737-
/* at-layer/001/a.css */
738715
@layer a;
739716

740717
/* at-layer/001/b.css */
@@ -754,7 +731,6 @@ TestCSSAtImportConditionsFromExternalRepo
754731
/* at-layer/001/style.css */
755732

756733
---------- /out/at-layer/002/style.css ----------
757-
/* at-layer/002/a.css */
758734
@media print {
759735
@layer a;
760736
}
@@ -776,7 +752,6 @@ TestCSSAtImportConditionsFromExternalRepo
776752
/* at-layer/002/style.css */
777753

778754
---------- /out/at-layer/003/style.css ----------
779-
/* at-layer/003/a.css */
780755
@layer a;
781756

782757
/* at-layer/003/b.css */
@@ -1609,6 +1584,36 @@ TestCSSAtImportExternal
16091584

16101585
/* entry.css */
16111586

1587+
================================================================================
1588+
TestCSSAtLayerBeforeImportBundle
1589+
---------- /out/entry.css ----------
1590+
@layer layer1, layer2.layer3;
1591+
1592+
/* a.css */
1593+
@layer layer4 {
1594+
a {
1595+
color: red;
1596+
}
1597+
}
1598+
1599+
/* b.css */
1600+
@layer layer5 {
1601+
b {
1602+
color: red;
1603+
}
1604+
}
1605+
1606+
/* entry.css */
1607+
@layer layer6.layer7, layer8;
1608+
1609+
================================================================================
1610+
TestCSSAtLayerBeforeImportNoBundle
1611+
---------- /out/entry.css ----------
1612+
@layer layer1, layer2.layer3;
1613+
@import "a.css";
1614+
@import "b.css";
1615+
@layer layer6.layer7, layer8;
1616+
16121617
================================================================================
16131618
TestCSSEntryPoint
16141619
---------- /out.css ----------

internal/helpers/strings.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ func StringArraysEqual(a []string, b []string) bool {
1717
return true
1818
}
1919

20+
func StringArrayArraysEqual(a [][]string, b [][]string) bool {
21+
if len(a) != len(b) {
22+
return false
23+
}
24+
for i, x := range a {
25+
if !StringArraysEqual(x, b[i]) {
26+
return false
27+
}
28+
}
29+
return true
30+
}
31+
2032
func StringArrayToQuotedCommaSeparatedString(a []string) string {
2133
sb := strings.Builder{}
2234
for i, str := range a {

0 commit comments

Comments
 (0)