Skip to content

feat(css): join adjacent rules and fold four more value spellings - #21648

Merged
alexander-akait merged 1 commit into
mainfrom
feat/css-minify-value-and-url-transforms
Aug 10, 2026
Merged

alexander-akait merged 1 commit into
mainfrom
feat/css-minify-value-and-url-transforms

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Aug 9, 2026 •

Copy link
Copy Markdown
Member

Summary

Continues the native CSS minifier's coverage of what the other minifiers ship, keeping webpack's rule that a rewrite must be equivalent to the engine. Measured over 18 real stylesheets (Bootstrap, Tailwind, Bulma, Foundation, UIkit, …): 4,519,478 → 4,505,803 raw / 540,124 → 539,417 gzip.

Structural: adjacent rules that print the same block join into one selector list, and adjacent at-rule blocks of one condition into one block — at every nesting depth, the rules the two blocks leave meeting at the seam joining the same way. Only where every selector is a shape each engine parses, since one it cannot invalidates the whole list. Rules a third stands between are still declined, that being a cascade reorder.

Values: a filter argument that is a zero carrying its unit; a data URI's payload written as the bytes its escapes name (outside that payload an escape is structure, so nothing else is touched); a shorthand slot holding its own initial where every value the slot takes is one the generated spellings report, not only where it takes keywords alone; flex's shrink factor over a basis no factor can be read as; and a gradient's last color-stop position where CSS Images 3 §3.4.3's own fix-up already puts it. Two adjacent stops of one color become the one stop naming both, behind a new output.environment.cssGradientDoublePosition, which the browserslist target reports like the other CSS abilities.

It also fixes a pre-existing bug the new nesting fixture caught: a declaration a nested rule parts from its repeat was dropped, losing a rule the engine builds.

What kind of change does this PR introduce?

feat

Did you add tests for your changes?

Yes — a new test/configCases/css/minimize-nesting case, plus fixtures in minimize-values, minimize-shorthands, minimize-urls, minimize-declined and minimize-environment, and ~90 cases in test/CssSyntax.unittest.js. Every transform is also checked against headless Chromium by test/SyntaxBrowserEquivalence.unittest.js, which must build the same rules in the same cascade order computing the same style from both spellings.

Does this PR introduce a breaking change?

No. output.environment.cssGradientDoublePosition is new and defaults to available, as the other CSS entries do.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

output.environment.cssGradientDoublePosition on the output.environment page, alongside cssColorHexAlpha / cssInsetShorthand / cssMediaQueryRange.

Use of AI

AI (Claude Code) was used to write the transforms, the generator's derivations and the tests, and to measure each change. No transform was kept on the model's word: every one had to pass the headless-Chromium equivalence suite, and every size claim in this description is a measured number over the 18-stylesheet corpus, reported whether or not it flattered the change — the gradient double-position fold is worth 16 raw bytes on it, and the seam join zero.


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Improved CSS minification for shorthand defaults, flex values, gradients, transforms, ratios, filter values, zero angles, keyframe selectors, and safe data-URI escapes.
    • Added removal of unnecessary background and mask defaults.
    • Added merging for compatible adjacent CSS rules and conditional at-rule blocks, including nested styles.
    • Added environment detection and configuration for two-position CSS gradient stops.
  • Bug Fixes

    • Preserved CSS cascade behavior and avoided unsafe transformations for unsupported browser targets or complex selectors.

@changeset-bot

changeset-bot Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 09aa8a2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
webpack Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "tools"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Adds CSS shorthand, URL, gradient, zero-value, transform, and keyframe minification. Adds adjacent qualified-rule and conditional at-rule merging with nesting and cascade safeguards. Adds generated CSS metadata, gradient capability detection, printer support, and validation fixtures.

Changes

CSS minification

Layer / File(s) Summary
CSS metadata generation
lib/css/data.js, tooling/generate-css-data.js, test/CssValueSyntax.unittest.js
Adds grammar-derived shorthand, gradient, alpha, ratio, and mergeable at-rule metadata with validation helpers and tests.
Minification and output processing
lib/css/syntax.js, lib/util/SourceProcessor.js, lib/css/cssMinify.js, types.d.ts
Adds CSS value transforms, safe data-URI decoding, gradient folding, buffered rule merging, cascade-aware declaration handling, and replacement-text printer operations.
Environment capability wiring
declarations/WebpackOptions.d.ts, schemas/WebpackOptions.json, lib/config/*, test/Defaults.unittest.js, test/configCases/ecmaVersion/*, test/configCases/css/minimize-environment/*
Adds cssGradientDoublePosition to public options, browser target detection, defaults, minimizer configuration, and snapshots.
Behavior validation and release metadata
test/CssSyntax.unittest.js, test/SyntaxBrowserEquivalence.unittest.js, test/configCases/css/*, .changeset/*
Adds unit, equivalence, nesting, URL, shorthand, gradient, selector, and rule-merging coverage. Updates changesets.
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title uses valid Conventional Commit syntax and describes the CSS rule joining and value-folding changes, but the branch prefix is not provided. Provide the branch name or confirm that its prefix is feat so the required type-prefix match can be verified.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (3197f80).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@3197f80
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@3197f80
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@3197f80

@codecov

codecov Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.44%. Comparing base (5c5d009) to head (09aa8a2).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21648      +/-   ##
==========================================
+ Coverage   94.40%   94.44%   +0.03%     
==========================================
  Files         628      628              
  Lines       80618    81097     +479     
  Branches    23812    23998     +186     
==========================================
+ Hits        76108    76592     +484     
+ Misses       4510     4505       -5     
Flag Coverage Δ
css-parsing 25.80% <14.89%> (-0.06%) ⬇️
html5lib 30.25% <27.27%> (+<0.01%) ⬆️
integration 88.43% <40.95%> (-0.20%) ⬇️
test262 49.09% <100.00%> (+<0.01%) ⬆️
unit 51.94% <100.00%> (+0.33%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Generated code size

Comparing 09aa8a2 against 5c5d009. Merging this PR will change the code webpack generates.

Changed New Deleted Unchanged Raw change
Cases 46 1 0 1478 🔴 ↑ +696 B
Assets 138 2 0 5802 🔴 ↑ +696 B
Runtimes 0 1 0 1863 —
140 asset(s) changed size, biggest 20 by raw change
Asset Before After Change Gzip (9) Brotli (11) Zstd (19)
➕ css/minimize-nesting bundle0.css — 2.78 KiB +2.78 KiB (new) new new new
🔴 ↑ css/minimize-values bundle0.css 15.23 KiB 17.48 KiB +2.25 KiB (+14.74%) +14.30% +14.80% +14.11%
🔴 ↑ css/minimize-shorthands bundle0.css 8.84 KiB 10.21 KiB +1.37 KiB (+15.47%) +16.14% +15.78% +15.48%
🟢 ↓ css/css-modules web-production/652.bundle1.css 27.57 KiB 26.61 KiB -987 B (-3.50%) -0.37% -0.40% -0.29%
🟢 ↓ css/css-modules web-production-global/244.bundle5.css 30.17 KiB 29.23 KiB -962 B (-3.11%) -0.38% -0.63% -0.33%
🔴 ↑ css/minimize-declined bundle0.css 3.88 KiB 4.81 KiB +952 B (+23.98%) +18.80% +19.16% +18.21%
🟢 ↓ css/escape-unescape 1/bundle1.css 1.51 KiB 878 B -664 B (-43.06%) -2.78% +1.19% -0.35%
🔴 ↑ css/minimize-urls bundle0.css 2.34 KiB 2.96 KiB +630 B (+26.28%) +35.58% +34.76% +37.50%
🔴 ↑ css/minimize-selectors bundle0.css 5.79 KiB 6.33 KiB +563 B (+9.50%) +15.08% +14.13% +14.84%
🟢 ↓ css/public-path 17/bundle17.css 882 B 518 B -364 B (-41.27%) -1.18% -2.99% -1.25%
🟢 ↓ css/public-path 15/bundle15.css 882 B 518 B -364 B (-41.27%) -1.18% -2.99% -1.25%
🟢 ↓ css/public-path 14/bundle14.css 882 B 518 B -364 B (-41.27%) -1.18% -2.99% -1.25%
🟢 ↓ css/public-path 16/bundle16.css 774 B 458 B -316 B (-40.83%) -0.62% +5.83% +0.67%
🟢 ↓ css/public-path 18/bundle18.css 774 B 458 B -316 B (-40.83%) -0.62% +5.83% +0.67%
🟢 ↓ css/public-path 8/bundle8.css 756 B 448 B -308 B (-40.74%) -0.63% +3.39% +0.67%
🟢 ↓ css/public-path 7/bundle7.css 756 B 448 B -308 B (-40.74%) -0.63% +3.39% +0.67%
🟢 ↓ css/public-path 4/bundle4.css 702 B 418 B -284 B (-40.46%) -0.65% +0.85% —
🟢 ↓ css/public-path 9/bundle9.css 702 B 418 B -284 B (-40.46%) -0.64% -1.68% +0.69%
🟢 ↓ css/public-path 6/bundle6.css 693 B 413 B -280 B (-40.40%) -0.65% +4.46% -0.69%
🔴 ↑ css/minimize-environment bundle0.css 1.22 KiB 1.49 KiB +274 B (+21.90%) +16.21% +18.26% +15.48%
… 120 more asset(s), see the uploaded report
1 runtime(s) changed which runtime modules they carry
Runtime Modules Added Removed
➕ css/minimize-nesting main 0 → 1 css loading —

Built test/configCases with the defaults a user gets: 1525 case(s), 5942 asset(s), 38 emitted nothing.

@codspeed

codspeed Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 43.98%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
✅ 217 untouched benchmarks

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ Memory benchmark "devtool-eval", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 949.8 KB 470.4 KB ×2
⚡ Memory benchmark "future-defaults", scenario '{"name":"mode-production","mode":"production"}' 10.2 MB 8.4 MB +21.79%
⚡ Memory benchmark "css-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 917.6 KB 756 KB +21.37%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing feat/css-minify-value-and-url-transforms (09aa8a2) with main (5c5d009)

Open in CodSpeed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (6)
test/CssSyntax.unittest.js (2)

2393-2403: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Give this block a distinct title.

Line 2401 uses the title template "keeps both rules where %s". Line 2318 already uses the same template in the same describe. Two cases can then report identical names. Rename the second block to name the nesting condition.

♻️ Proposed rename
-		])("keeps both rules where %s", (_name, css) => {
+		])("keeps both nested rules where %s", (_name, css) => {

2167-2169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Two new inline comments exceed the comment-length limit. The guideline allows one line, and two short lines at most. Both comments span three lines.

  • test/CssSyntax.unittest.js#L2167-L2169: shorten the <bg-image> slot explanation to two short lines.
  • test/SyntaxBrowserEquivalence.unittest.js#L1024-L1026: shorten the adjacent-repeat explanation to two short lines.

As per coding guidelines: "Keep comments as short as possible, generally one line and no more than two short lines; comments must add non-obvious information and must not narrate or restate code."

Source: Coding guidelines

test/configCases/css/minimize-nesting/webpack.config.js (1)

25-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the specific Compiler JSDoc type.

EXPECTED_ANY disables type checking at the MinimizerPlugin.apply boundary. Replace it with import("../../../../").Compiler, if that type is compatible with the installed plugin declaration.

Proposed change
- }).apply(/** `@type` {EXPECTED_ANY} */ (compiler));
+ }).apply(/** `@type` {import("../../../../").Compiler} */ (compiler));

As per coding guidelines, use EXPECTED_ANY only when a precise type is genuinely unavailable.

Source: Coding guidelines

lib/css/syntax.js (3)

6643-6653: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the CC_ character-code constants.

This loop compares against the numeric literals 0x28 and 0x29. The file names character codes elsewhere, for example CC_SEMICOLON at Line 7964 and CC_QUOTATION_MARK at Line 5739. Use the same named constants for ( and ) if they exist in this module.


7646-7653: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Chain the two gradient transforms instead of returning after the first.

_dropDefaultGradientDirection returns as soon as it changes anything, so _foldGradientStops never runs on the same value. For linear-gradient(to bottom,red,blue 100%) the default direction is dropped and the redundant 100% is kept, because the printer visits the node once.

Feed the first result into the second.

♻️ Proposed change
-				const gradient = _dropDefaultGradientDirection(fn, inner);
-				if (gradient !== null) return `${name}(${gradient})`;
-				const stops = _foldGradientStops(
-					fn,
-					inner,
-					_doublePositionAllowed(writer)
-				);
-				if (stops !== null) return `${name}(${stops})`;
+				const gradient = _dropDefaultGradientDirection(fn, inner);
+				const args = gradient === null ? inner : gradient;
+				const stops = _foldGradientStops(
+					fn,
+					args,
+					_doublePositionAllowed(writer)
+				);
+				if (stops !== null) return `${name}(${stops})`;
+				if (gradient !== null) return `${name}(${gradient})`;

7934-7952: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Skip the allocation when the rule cannot contain a duplicate.

superseded and seen are allocated for every minified rule, including the many rules that hold zero or one item. The printer runs once per rule, so this is a hot path.

Guard both allocations on items.length >= 2.

♻️ Proposed change
 			/** `@type` {Set<number> | null} */
 			let superseded = null;
-			if (minify) {
+			if (minify && items.length >= 2) {
 				superseded = new Set();

As per coding guidelines: "Evaluate time and memory costs of changes, especially on hot paths."

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c712655c-bff0-4d71-97b3-38d41f76d8b1

📥 Commits

Reviewing files that changed from the base of the PR and between 267ef49 and 31498ac.

⛔ Files ignored due to path filters (18)
  • test/__snapshots__/Cli.basictest.js.snap is excluded by !**/*.snap
  • test/__snapshots__/target-browserslist.unittest.js.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-colors/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-colors/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-declined/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-declined/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-environment/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-environment/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-nesting/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-nesting/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-shorthands/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-shorthands/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-urls/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-urls/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-values/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-values/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
📒 Files selected for processing (38)
  • .changeset/070-css-html-minify-transforms.md
  • .changeset/075-css-join-adjacent-rules.md
  • declarations/WebpackOptions.d.ts
  • lib/config/browserslistTargetHandler.js
  • lib/config/defaults.js
  • lib/config/target.js
  • lib/css/cssMinify.js
  • lib/css/data.js
  • lib/css/syntax.js
  • lib/util/SourceProcessor.js
  • schemas/WebpackOptions.check.js
  • schemas/WebpackOptions.json
  • test/CssSyntax.unittest.js
  • test/CssValueSyntax.unittest.js
  • test/Defaults.unittest.js
  • test/SyntaxBrowserEquivalence.unittest.js
  • test/configCases/css/minimize-declined/style.css
  • test/configCases/css/minimize-environment/style.css
  • test/configCases/css/minimize-environment/webpack.config.js
  • test/configCases/css/minimize-nesting/index.js
  • test/configCases/css/minimize-nesting/style.css
  • test/configCases/css/minimize-nesting/test.config.js
  • test/configCases/css/minimize-nesting/webpack.config.js
  • test/configCases/css/minimize-selectors/style.css
  • test/configCases/css/minimize-shorthands/style.css
  • test/configCases/css/minimize-urls/style.css
  • test/configCases/css/minimize-values/style.css
  • test/configCases/ecmaVersion/browserslist-config-env-extends/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-config-env/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-config-extends/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-config/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-env/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-extends/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-query-with-config-file/webpack.config.js
  • test/configCases/ecmaVersion/browserslist-query/webpack.config.js
  • test/configCases/ecmaVersion/browserslist/webpack.config.js
  • tooling/generate-css-data.js
  • types.d.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • webpack/schema-utils (auto-detected)
  • webpack/tapable (auto-detected)

Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread test/CssValueSyntax.unittest.js Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
lib/css/syntax.js (2)

6612-6613: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use full identifier names.

Rename fn and out to names such as functionName and reducedFunction.

As per coding guidelines, “Spell function, variable, parameter, and property names out in full.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/css/syntax.js` around lines 6612 - 6613, In _reduceTransformFunctionDeep,
rename the abbreviated parameter fn and local variable out to full descriptive
identifiers such as functionName and reducedFunction, updating all references
while preserving the existing behavior.

Source: Coding guidelines


6575-6577: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shorten these source comments.

  • lib/css/syntax.js#L6575-L6577: Reduce the comment to one or two short lines.
  • lib/css/syntax.js#L6588-L6590: Reduce the comment to one or two short lines.
  • lib/css/syntax.js#L6605-L6607: Reduce the comment to one or two short lines.
  • lib/css/syntax.js#L6660-L6662: Reduce the comment to one or two short lines.

As per coding guidelines, comments must generally use one line and no more than two short lines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/css/syntax.js` around lines 6575 - 6577, Shorten the source comments at
lib/css/syntax.js lines 6575-6577, 6588-6590, 6605-6607, and 6660-6662 to one or
two concise lines while preserving their essential clarification.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/css/syntax.js`:
- Around line 6593-6597: Update the layer transformation in the relevant
background/mask size parser so it removes the trailing auto only when the first
token is a valid size value; preserve cover, contain, and CSS-wide keywords such
as initial as invalid two-token declarations. Add regression cases covering
these inputs and verify invalid declarations are not reduced to valid one-token
values.

---

Nitpick comments:
In `@lib/css/syntax.js`:
- Around line 6612-6613: In _reduceTransformFunctionDeep, rename the abbreviated
parameter fn and local variable out to full descriptive identifiers such as
functionName and reducedFunction, updating all references while preserving the
existing behavior.
- Around line 6575-6577: Shorten the source comments at lib/css/syntax.js lines
6575-6577, 6588-6590, 6605-6607, and 6660-6662 to one or two concise lines while
preserving their essential clarification.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f06609a-3f94-4f1a-bdcd-f2165ba0a0a8

📥 Commits

Reviewing files that changed from the base of the PR and between 1af5013 and cb48da8.

⛔ Files ignored due to path filters (2)
  • test/configCases/css/minimize-values/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-values/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • .changeset/070-css-html-minify-transforms.md
  • lib/css/syntax.js
  • test/CssSyntax.unittest.js
  • test/configCases/css/minimize-values/style.css
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • webpack/schema-utils (auto-detected)
  • webpack/tapable (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/070-css-html-minify-transforms.md

Comment thread lib/css/syntax.js Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/css/syntax.js (1)

8058-8062: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve kept comments at the full custom-property value boundaries.

from and to exclude comment-only gaps before the first token and after the last token. A kept /*!…*/ comment in either gap remains queued and can be emitted after the enclosing rule instead of inside --x.

Pass the complete declaration-value span to _customPropertyValue. Add regression cases for --x:/*!keep*/foo and --x:foo/*!keep*/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/css/syntax.js` around lines 8058 - 8062, Update the custom-property
handling around _customPropertyValue to pass the complete declaration-value
span, including comment-only gaps before the first child and after the last
child, rather than boundaries derived solely from children. Preserve the
non-minified slicing behavior as appropriate, and add regression coverage for
--x:/*!keep*/foo and --x:foo/*!keep*/ so kept comments remain inside the
custom-property value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@lib/css/syntax.js`:
- Around line 8058-8062: Update the custom-property handling around
_customPropertyValue to pass the complete declaration-value span, including
comment-only gaps before the first child and after the last child, rather than
boundaries derived solely from children. Preserve the non-minified slicing
behavior as appropriate, and add regression coverage for --x:/*!keep*/foo and
--x:foo/*!keep*/ so kept comments remain inside the custom-property value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad9eb090-5137-4668-878c-fb1d47c11e6e

📥 Commits

Reviewing files that changed from the base of the PR and between cb48da8 and 95910a8.

⛔ Files ignored due to path filters (4)
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-values/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap
  • test/configCases/css/minimize-values/__snapshots__/ConfigTest.snap is excluded by !**/*.snap
📒 Files selected for processing (10)
  • .changeset/070-css-html-minify-transforms.md
  • lib/css/data.js
  • lib/css/syntax.js
  • lib/util/SourceProcessor.js
  • test/CssSyntax.unittest.js
  • test/CssValueSyntax.unittest.js
  • test/configCases/css/minimize-selectors/style.css
  • test/configCases/css/minimize-values/style.css
  • tooling/generate-css-data.js
  • types.d.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • webpack/schema-utils (auto-detected)
  • webpack/tapable (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (5)
  • lib/util/SourceProcessor.js
  • types.d.ts
  • .changeset/070-css-html-minify-transforms.md
  • lib/css/data.js
  • test/configCases/css/minimize-selectors/style.css

@github-actions github-actions Bot added area: config Options, defaults, validation (lib/config, schemas/) area: css CSS support (lib/css) area: types types.d.ts, JSDoc annotations, hand-maintained declarations area: tooling Repo tooling, codegen, CLI entry (tooling/, bin/) labels Aug 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tooling/generate-css-data.js (1)

792-794: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shorten this comment.

Use no more than two short lines for this comment.

Proposed change
-			// A grammar naming its slots by type rather than by property: the slot
-			// is the longhand whose own value is exactly that type, followed
-			// through the `<'other'>` some of them are stated as.
+			// Match a type slot to the unique longhand whose complete value has that type.
+			// Follow a `<'other'>` reference before matching.

As per coding guidelines, "{lib,hot,tooling,test}/**/*.{js,mjs}: Keep comments as short as possible, generally one line and no more than two short lines; comments must add non-obvious information and must not narrate or restate code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tooling/generate-css-data.js` around lines 792 - 794, Shorten the comment
near the grammar slot handling to no more than two brief lines, retaining only
the non-obvious explanation that the slot is the longhand whose value matches
the grammar type.

Source: Coding guidelines

test/SyntaxBrowserEquivalence.unittest.js (1)

432-435: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shorten the changed comments.

Reduce these comments to no more than two short lines each. Keep only the cascade behavior that is not clear from the code.

As per coding guidelines, “Keep comments as short as possible, generally one line and no more than two short lines; comments must add non-obvious information and must not narrate or restate code.”

Also applies to: 443-447

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/SyntaxBrowserEquivalence.unittest.js` around lines 432 - 435, Shorten
the comments around the selector cascade behavior near the existing probe
explanation, including the related comment at the other referenced section, to
no more than two short lines each. Retain only the non-obvious rule that later
declarations win and !important declarations take precedence; remove narrative
about joining blocks, text folding, or restating the code.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/SyntaxBrowserEquivalence.unittest.js`:
- Around line 439-441: Update the adjacent-rule equivalence check in walk() to
compare previous.chain and chain by their condition entries’ kind and condition
values rather than array identity. Preserve the existing previous and label
checks so equivalent adjacent conditional blocks are merged while distinct
chains remain separate.

---

Nitpick comments:
In `@test/SyntaxBrowserEquivalence.unittest.js`:
- Around line 432-435: Shorten the comments around the selector cascade behavior
near the existing probe explanation, including the related comment at the other
referenced section, to no more than two short lines each. Retain only the
non-obvious rule that later declarations win and !important declarations take
precedence; remove narrative about joining blocks, text folding, or restating
the code.

In `@tooling/generate-css-data.js`:
- Around line 792-794: Shorten the comment near the grammar slot handling to no
more than two brief lines, retaining only the non-obvious explanation that the
slot is the longhand whose value matches the grammar type.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9b7d3494-f421-4bd8-b0f7-71446e2d34ae

📥 Commits

Reviewing files that changed from the base of the PR and between 95910a8 and 49d9291.

⛔ Files ignored due to path filters (5)
  • lib/css/data.js is excluded by !lib/css/data.js
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
  • test/configCases/css/minimize-selectors/__snapshots__/ConfigTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
  • test/configCases/css/minimize-shorthands/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
  • test/configCases/css/minimize-shorthands/__snapshots__/ConfigTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
📒 Files selected for processing (8)
  • .changeset/075-css-join-adjacent-rules.md
  • lib/css/syntax.js
  • test/CssSyntax.unittest.js
  • test/CssValueSyntax.unittest.js
  • test/SyntaxBrowserEquivalence.unittest.js
  • test/configCases/css/minimize-selectors/style.css
  • test/configCases/css/minimize-shorthands/style.css
  • tooling/generate-css-data.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • webpack/schema-utils (auto-detected)
  • webpack/tapable (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (3)
  • test/configCases/css/minimize-selectors/style.css
  • .changeset/075-css-join-adjacent-rules.md
  • lib/css/syntax.js

@alexander-akait
alexander-akait force-pushed the feat/css-minify-value-and-url-transforms branch 2 times, most recently from 1711e88 to 6a8cafe Compare August 9, 2026 22:58
Join adjacent qualified rules that share a selector, the blocks of two
adjacent at-rules of one condition, and a border side's three longhands
into its shorthand, each declining wherever the cascade could read the
result differently.

Fold a one-axis skew and rotation, an alpha percentage, a ratio's
implied denominator, a gradient's defaulted stop positions and a data
URI's needless escapes, and reduce a transform until it stops getting
shorter.
@alexander-akait
alexander-akait force-pushed the feat/css-minify-value-and-url-transforms branch from 6a8cafe to 09aa8a2 Compare August 9, 2026 23:08
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging feat/css-minify-value-and-url-transforms into main will be
99.29%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.82%100%100%98.82%103
examples
   build-common.js100%100%100%100%
   buildAll.js100%100%100%100%
   examples.js100%100%100%100%
   template-common.js98.21%100%100%98.21%72
examples/custom-javascript-parser
   test.filter.js100%100%100%100%
examples/custom-javascript-parser/internals
   acorn-parse.js100%100%100%100%
   meriyah-parse.js100%100%100%100%
   oxc-parse.js100%100%100%100%
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/module-federation
   test.filter.js100%100%100%100%
examples/reexport-components
   test.filter.js100%100%100%100%
examples/typescript
   test.filter.js100%100%100%100%
examples/typescript-non-erasable
   test.filter.js50%100%100%50%5
examples/virtual-modules
   test.filter.js100%100%100%100%
examples/wasm-bindgen-esm
   test.filter.js100%100%100%100%
examples/wasm-complex
   test.filter.js100%100%100%100%
examples/wasm-emscripten
   test.filter.js100%100%100%100%
examples/wasm-simple
   test.filter.js100%100%100%100%
examples/wasm-simple-source-phase
   test.filter.js100%100%100%100%
lib
   APIPlugin.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%101
   CacheFacade.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%39
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CircularModulesPlugin.js98.81%100%100%98.81%136
   CleanPlugin.js99.12%100%100%99.12%214, 234
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.42%100%100%98.42%1648, 1967, 1974, 1982, 2004, 2007, 2946, 3425–3426, 3458, 4162, 4192, 4245–4246, 4250, 4255, 4271–4272, 4286–4287, 4292–4293, 4773, 4799, 527, 532, 5607, 5639, 5656, 5672, 5688, 5703, 5728–5729, 5731, 6061, 6066, 6072, 6075, 6082, 6094, 6096, 6100, 6116, 6131, 6163, 6217, 6241, 6356, 778–779
   Compiler.js99.56%100%100%99.56%1159–1160, 1168
   ConcatenationScope.js99.12%100%100%99.12%300
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js99.88%100%100%99.88%1461
   ContextModuleFactory.js97.20%100%100%97.20%266, 435, 456, 461, 501, 512, 514, 518, 527–528
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99.08%100%100%99.08%1080, 176–177, 193, 212, 286
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.51%100%100%98.51%480, 527
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js98.41%100%100%98.41%378, 391–392
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%49
   ErrorHelpers.js100%100%100%100%
   EvalDevToolModulePlugin.js100%100%100%100%
   EvalSourceMapDevToolPlugin.js100%100%100%100%
   ExportsInfo.js100%100%100%100%
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.67%100%100%98.67%1216, 1219, 515–519, 521, 667
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.16%100%100%99.16%1267, 1269–1274, 1281, 1284, 182, 2502–2503, 2506, 2517, 2528, 2539, 280, 3976, 3991, 4015
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.36%100%100%98.36%504, 513, 516, 520, 532
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LazyBarrel.js100%100%100%100%
   LibraryTemplatePlugin.js100%100%100%100%
   LoaderOptionsPlugin.js100%100%100%100%
   LoaderTargetPlugin.js100%100%100%100%
   MainTemplate.js100%100%100%100%
   ManifestPlugin.js100%100%100%100%
   Module.js98.51%100%100%98.51%1303, 1308, 1368, 1382, 1444, 1453
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.90%100%100%98.90%111, 113
   ModuleGraph.js99.78%100%100%99.78%1170
   ModuleGraphConnection.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   MultiCompiler.js99.72%100%100%99.72%716
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.98%100%100%97.98%1020, 1023, 1040, 1057, 1305, 1339, 1355, 1803, 2100, 2105–2115, 34
   NormalModuleFactory.js98.72%100%100%98.72%1123, 1391, 1402, 1412, 1463–1465, 1472, 526, 538
   NormalModuleReplacementPlugin.js100%100%100%100%
   NullFactory.js100%100%100%100%
   OptimizationStages.js100%100%100%100%
   OptionsApply.js100%100%100%100%
   Parser.js100%100%100%100%
   PlatformPlugin.js100%100%100%100%
   PrefetchPlugin.js100%100%100%100%
   ProgressPlugin.js99.80%100%100%99.80%691
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   ResolverFactory.js100%100%100%100%
   RuntimeGlobals.js100%100%100%100%
   RuntimeModule.js100%100%100%100%
   RuntimePlugin.js100%100%100%100%
   RuntimeTemplate.js100%100%100%100%
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js98.63%100%100%98.63%220, 224, 226, 420, 431, 890
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.47%100%100%99.47%352–353
   UseStrictPlugin.js100%100%100%100%
   WarnCaseSensitiveModulesPlugin.js100%100%100%100%
   WarnDeprecatedOptionPlugin.js100%100%100%100%
   WarnNoModeSetPlugin.js100%100%100%100%
   WatchIgnorePlugin.js100%100%100%100%
   Watching.js100%100%100%100%
   WebpackError.js100%100%100%100%
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%371
   cli.js98.63%100%100%98.63%10, 119, 549, 581, 631, 905
   index.js99.73%100%100%99.73%184
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js97.10%100%100%97.10%10, 263, 285, 287
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js97.95%100%100%97.95%295, 319, 322, 42, 452, 47
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
   WebManifestGenerator.js100%100%100%100%
   WebManifestParser.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
   isGeneratorLowered.js100%100%100%100%
lib/bun
   BunTargetPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%75, 87, 95
   MemoryCachePlugin.js92%100%100%92%34, 43
   MemoryWithGcCachePlugin.js93.42%100%100%93.42%108, 122–123, 132, 90
   PackFileCacheStrategy.js96.52%100%100%96.52%1310, 1410, 1414, 1476, 1712, 1796, 1819, 1851, 675, 694, 704–706, 708, 724–725, 730, 733, 735, 740, 745, 770, 776, 810, 816, 822, 827, 838, 847, 852–853, 855, 872, 878–879, 881
   ResolverCachePlugin.js100%100%100%100%
   

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: config Options, defaults, validation (lib/config, schemas/) area: css CSS support (lib/css) area: tooling Repo tooling, codegen, CLI entry (tooling/, bin/) area: types types.d.ts, JSDoc annotations, hand-maintained declarations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant