From eb667c35bd1c32b3ea2fc5f56326665298131b3a Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Fri, 11 Aug 2023 20:39:34 -0400 Subject: [PATCH] css: try to merge adjacent `@layer` rules together --- internal/bundler_tests/bundler_css_test.go | 34 +++++++++++++++++++ .../bundler_tests/snapshots/snapshots_css.txt | 33 +++++++++++++++--- internal/linker/linker.go | 21 ++++++++++++ 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/internal/bundler_tests/bundler_css_test.go b/internal/bundler_tests/bundler_css_test.go index 87c26ee4302..dc6d601c26a 100644 --- a/internal/bundler_tests/bundler_css_test.go +++ b/internal/bundler_tests/bundler_css_test.go @@ -2537,3 +2537,37 @@ func TestCSSAtLayerBeforeImportBundle(t *testing.T) { }, }) } + +func TestCSSAtLayerMergingWithImportConditions(t *testing.T) { + css_suite.expectBundled(t, bundled{ + files: map[string]string{ + "/entry.css": ` + @import "a.css" supports(color: first); + + @import "a.css" supports(color: second); + @import "b.css" supports(color: second); + + @import "a.css" supports(color: first); + @import "b.css" supports(color: first); + + @import "a.css" supports(color: second); + @import "b.css" supports(color: second); + + @import "b.css" supports(color: first); + `, + "/a.css": ` + @layer a; + @import "http://example.com/a.css"; + `, + "/b.css": ` + @layer b; + @import "http://example.com/b.css"; + `, + }, + entryPaths: []string{"/entry.css"}, + options: config.Options{ + Mode: config.ModeBundle, + AbsOutputDir: "/out", + }, + }) +} diff --git a/internal/bundler_tests/snapshots/snapshots_css.txt b/internal/bundler_tests/snapshots/snapshots_css.txt index 171ba696589..a7139abdeda 100644 --- a/internal/bundler_tests/snapshots/snapshots_css.txt +++ b/internal/bundler_tests/snapshots/snapshots_css.txt @@ -250,8 +250,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile /* case2.css */ ---------- /out/case3.css ---------- -@layer first; -@layer last; +@layer first, last; /* a.css */ @layer first { @@ -289,8 +288,7 @@ TestCSSAtImportConditionsAtLayerBundleAlternatingLayerInFile /* case4.css */ ---------- /out/case5.css ---------- -@layer first; -@layer last; +@layer first, last; /* a.css */ @layer first { @@ -1614,6 +1612,33 @@ TestCSSAtLayerBeforeImportNoBundle @import "b.css"; @layer layer6.layer7, layer8; +================================================================================ +TestCSSAtLayerMergingWithImportConditions +---------- /out/entry.css ---------- +@supports (color: first) { + @layer a; +} +@import "http://example.com/a.css" supports(color: first); +@import "http://example.com/a.css" supports(color: second); +@import "http://example.com/b.css" supports(color: second); +@import "http://example.com/b.css" supports(color: first); +@supports (color: second) { + @layer a, b; +} + +/* a.css */ +@supports (color: first) { + @layer b; +} + +/* a.css */ + +/* b.css */ + +/* b.css */ + +/* entry.css */ + ================================================================================ TestCSSEntryPoint ---------- /out.css ---------- diff --git a/internal/linker/linker.go b/internal/linker/linker.go index 5968f9d03e3..2385735e835 100644 --- a/internal/linker/linker.go +++ b/internal/linker/linker.go @@ -3703,6 +3703,27 @@ func (c *linkerContext) findImportedFilesInCSSOrder(entryPoints []uint32) (order wipOrder = append(wipOrder, entry) } + order, wipOrder = wipOrder, order[:0] + } + + // Finally, merge adjacent "@layer" rules with identical conditions together. + { + didClone := -1 + for _, entry := range order { + if entry.kind == cssImportLayers && len(wipOrder) > 0 { + prevIndex := len(wipOrder) - 1 + prev := wipOrder[prevIndex] + if prev.kind == cssImportLayers && importConditionsAreEqual(prev.conditions, entry.conditions) { + if didClone != prevIndex { + didClone = prevIndex + prev.layers = append([][]string{}, prev.layers...) + } + wipOrder[prevIndex].layers = append(prev.layers, entry.layers...) + continue + } + } + wipOrder = append(wipOrder, entry) + } order = wipOrder }