Skip to content

feat(minify): add and drop CSS vendor prefixes for the browserslist target - #21602

Closed
aryanraj45 wants to merge 5 commits into
webpack:mainfrom
aryanraj45:feat/css-vendor-prefixes
Closed

aryanraj45 wants to merge 5 commits into
webpack:mainfrom
aryanraj45:feat/css-vendor-prefixes

Conversation

@aryanraj45

@aryanraj45 aryanraj45 commented Aug 4, 2026 •

Copy link
Copy Markdown
Member

Summary

Native CSS minification now maintains vendor prefixes for the browserslist target: when the default minimizer runs, it adds the -webkit- / -moz- / -ms- spellings the selected browsers still need and drops the ones none of them do. It covers all three axes a prefix appears on:

  • properties — user-select: none → -webkit-user-select / -moz-user-select added for old targets; a dead -webkit-border-radius dropped for modern ones
  • at-rules — @keyframes gains a @-webkit-keyframes copy when needed
  • pseudo-selectors — ::placeholder → ::-webkit-input-placeholder, keeping the author's colons

The prefix table is generated from @mdn/browser-compat-data at build time into lib/css/data.js (like every other CSS lookup table), so syntax.js stays algorithm-only and a data-package bump lands as a reviewable diff. Each browser is filtered to its own engine's prefix, so obsolete cross-engine ones (e.g. -khtml-) are never emitted. At-rule and selector siblings are tracked with a small running set of top-level rules as the printer streams — no whole-stylesheet buffer, so peak heap stays flat.

Scope note: this is the prefixes half of the two-part plan. Modern↔legacy value-syntax rewriting (e.g. gradient direction) is a separate follow-up, since prefixing those requires argument transforms rather than a prefix.

What kind of change does this PR introduce?

feat

Did you add tests for your changes?

Yes. test/CssSyntax.unittest.js adds 28 unit cases across the three axes (add, remove, no-double, minor-version boundaries, version ranges, Safari TP, selector-list skip, off-without-target), and test/configCases/css/minimize-vendor-prefixes drives a real browserslist build exercising all three axes end to end.

Does this PR introduce a breaking change?

No.

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

The CSS minifier now adds/removes vendor prefixes automatically based on the resolved browserslist target; there is no new configuration option.

Use of AI
Yes


Note

Medium Risk
Changes emitted CSS for production builds with browserslist targets and large generated compat tables; incorrect prefix logic could break styles in older browsers, though behavior is gated on environment.browsers and covered by unit and config-case tests.

Overview
CSS minification now adds and removes vendor prefixes based on the resolved browserslist target when the default minimizer runs—no new user option.

Wiring: getTargetsBrowsers() merges browsers from browserslist targets; the default minimizer passes that list as environment.browsers into CSS and HTML minify (inline styles stay aligned).

Data: tooling/generate-css-data.js builds PREFIXED_PROPERTIES, PREFIXED_SELECTORS, and PREFIXED_AT_RULES from @mdn/browser-compat-data into lib/css/data.js. Prefix need is decided per browser version window; only each engine’s own prefixes are considered (obsolete cross-engine spellings like -khtml- are not emitted).

Minify behavior in lib/css/syntax.js when environment.browsers is set:

  • Declarations: insert missing prefixed properties before unprefixed ones; drop redundant prefixed declarations when every target is covered by the unprefixed form.
  • Top-level at-rules (e.g. @keyframes): prepend needed prefixed copies; drop prefixed rules superseded by an unprefixed sibling.
  • Top-level single-pseudo selectors (e.g. ::placeholder): same add/drop pattern; comma-separated selector lists are left unchanged.

Without a browserslist-backed browser list, prefix handling is unchanged. Types document optional CssEnvironment.browsers.

Reviewed by Cursor Bugbot for commit 1496047. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • CSS minification now automatically adds required vendor prefixes based on configured browser targets.
    • Removes unnecessary prefixes from CSS properties, at-rules, and pseudo-selectors.
    • Supports browser-specific handling for animations, user-select, appearance, placeholders, and related CSS features.
  • Bug Fixes

    • Prevents duplicate or unsupported prefixed rules while preserving declarations required by selected browsers.
    • Leaves CSS unchanged when no browser targets are configured.

@changeset-bot

changeset-bot Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2318c90

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

Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
@aryanraj45
aryanraj45 force-pushed the feat/css-vendor-prefixes branch from e31719f to 5b82e0b Compare August 4, 2026 13:14
@codecov

codecov Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.89706% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.22%. Comparing base (9d3b707) to head (1496047).
⚠️ Report is 37 commits behind head on main.

Files with missing lines Patch % Lines
lib/css/syntax.js 98.90% 2 Missing ⚠️
lib/config/defaults.js 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #21602      +/-   ##
==========================================
+ Coverage   94.21%   94.22%   +0.01%     
==========================================
  Files         628      628              
  Lines       78998    79268     +270     
  Branches    23304    23405     +101     
==========================================
+ Hits        74425    74692     +267     
- Misses       4573     4576       +3     
Flag Coverage Δ
css-parsing 26.00% <17.07%> (-0.04%) ⬇️
html5lib 27.37% <81.25%> (+<0.01%) ⬆️
integration 88.93% <23.90%> (-0.18%) ⬇️
test262 49.22% <81.25%> (+0.01%) ⬆️
unit 51.86% <98.16%> (+0.18%) ⬆️

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.

@codspeed

codspeed Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ 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
❌ 1 regressed benchmark
✅ 216 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ Memory benchmark "many-modules-interop-runtime", scenario '{"name":"mode-production","mode":"production"}', measure 'exec' 18.9 KB 25.3 KB -25.36%
⚡ Memory benchmark "react", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 809.2 KB 240.9 KB ×3.4
⚡ Memory benchmark "three-long", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 1,158.2 KB 706.1 KB +64.04%
⚡ Memory benchmark "css-modules", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 923.3 KB 751.6 KB +22.86%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing aryanraj45:feat/css-vendor-prefixes (1496047) with main (9d3b707)

Open in CodSpeed

@aryanraj45
aryanraj45 force-pushed the feat/css-vendor-prefixes branch from 5b82e0b to 1496047 Compare August 5, 2026 09:16
@aryanraj45

Copy link
Copy Markdown
Member Author

@alexander-akait rebased into main can u please re-run the ci again thanks :))

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1496047. Configure here.

Comment thread lib/css/syntax.js Resolved
…list target

Generate a prefix table from @mdn/browser-compat-data at build time and, when the
default minimizer runs for a browserslist target, add the -webkit-/-moz-/-ms-
spellings the selected browsers still need and drop the ones none do. Covers
properties, at-rules and pseudo-selectors; sibling awareness for at-rules and
selectors uses a small running set of top-level rules, not a whole-stylesheet
buffer, so the streaming printer's peak-heap stays flat.
…ensitively

Two prefixing bugs: a later at-rule or pseudo-selector with the same signature as an
earlier one no longer skips its prefixed copy, so a rule that overrides an earlier
keeps its prefixed twin winning too; and a pseudo name is lowercased before the
table lookup, so an ASCII case variant like ::PLACEHOLDER is prefixed like the
lowercase spelling, as property and at-rule names already are.
An at-rule name is case-insensitive, so a cased `@Keyframes` and a prefixed
`@-webkit-keyframes` must share one signature. The unprefixed branch keyed the raw
prelude, which kept the author's case, so the two never paired — a prefixed copy was
duplicated or a dead one left in. Key both off the lowercased `@base` spelling.
…eudos

Two edge cases: the sibling set that tracks at-rules and selectors has no nesting
key, so restrict rule-level prefixing to top-level rules — a nested `@keyframes` or
pseudo no longer adds or drops against a same-named top-level rule in another scope
(a nested rule's declarations are still prefixed). And a functional pseudo like
`:dir(rtl)` prints as one token, so match and rewrite its name apart from the
argument, which is kept in the sibling signature so `:dir(rtl)` and `:dir(ltr)`
stay distinct.
@aryanraj45
aryanraj45 force-pushed the feat/css-vendor-prefixes branch from 1496047 to 1bb4658 Compare August 10, 2026 15:10
@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 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

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

Webpack resolves Browserslist targets and passes them to CSS and HTML minimizers. CSS minification adds required vendor prefixes and removes redundant prefixes for declarations, at-rules, and selectors. MDN Browser Compatibility Data supplies the compatibility tables.

Changes

CSS vendor-prefix minification

Layer / File(s) Summary
Browser target resolution
lib/config/target.js, lib/config/defaults.js
Browserslist targets are parsed, loaded, deduplicated, and passed to minimizer environments.
Prefix compatibility data
tooling/generate-css-data.js, package.json
MDN compatibility data generates prefix tables for properties, selectors, and at-rules.
CSS prefix processing
lib/css/syntax.js
The CSS printer removes unnecessary prefixes and generates required prefixed declarations, rules, and selectors.
Validation and release support
test/CssSyntax.unittest.js, test/configCases/css/minimize-vendor-prefixes/*, .changeset/158-css-vendor-prefixes.md, cspell.json
Tests cover target-driven prefix handling. The configuration fixture and release metadata describe the behavior.

Possibly related PRs

Suggested reviewers: alexander-akait, bjohansebas

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title follows the conventional-commit format and accurately describes the CSS vendor-prefix change, but the branch prefix is not provided for verification. Provide the branch name or branch prefix 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.

@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 (8)
test/CssSyntax.unittest.js (2)

4316-4320: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hoist the triplicated minify helper.

The three new describe blocks each define a byte-identical helper. Define it once above them and share it.

Also applies to: 4436-4440, 4518-4522

🤖 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/CssSyntax.unittest.js` around lines 4316 - 4320, Hoist the identical
minify helper from the three describe blocks into a single shared definition
above them in the test module. Remove each local duplicate and have all three
blocks reuse the shared minify function, preserving its existing SourceProcessor
configuration and return behavior.

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

No test covers the prefixed-first rule order, which is the order authors write.

Both rule-level removal tests place the unprefixed rule first. _prefixAtRule and _prefixQualifiedRule remove a prefixed rule only when seen.has(signature) already holds (lines 5980 and 6094), so removal depends on the unprefixed twin being printed first. The streaming printer cannot look ahead, and the comment at line 5959 states this constraint.

Prefix fallbacks are conventionally authored prefixed-first, so the untested order is the common input, and in it no removal happens. Declarations are unaffected: present is built from all declarations before the loop at lines 9225-9229, so declaration removal is order-independent.

Add a case that pins the prefixed-first behavior. That documents the limitation and catches a future change to it.

💚 Pin the documented order dependency
+	it("keeps a prefixed at-rule written before its unprefixed twin — streaming cannot look ahead", () => {
+		expect(
+			minify("`@-webkit-keyframes` s{to{opacity:1}}`@keyframes` s{to{opacity:1}}", [
+				"chrome 120"
+			])
+		).toBe("`@-webkit-keyframes` s{to{opacity:1}}`@keyframes` s{to{opacity:1}}");
+	});

As per path instructions: "Cover every changed line and branch with tests, preferably through integration cases."

Also applies to: 4548-4554

🤖 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/CssSyntax.unittest.js` around lines 4462 - 4468, Add test coverage for
prefixed-first ordering in the rule-level at-rule removal tests near the
existing prefixed/unprefixed cases: place the prefixed `@-webkit-keyframes` rule
before its unprefixed `@keyframes` twin and assert the current streaming behavior,
preserving the documented order dependency. Apply the same coverage to the
corresponding test around the alternate referenced range, without changing
implementation behavior.

Source: Path instructions

tooling/generate-css-data.js (4)

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

The comment claims a standard-status filter that collectPrefixTable does not implement.

The comment states "Standard entries only — a construct BCD marks non-standard is a vendor's own, not a spelling of a standard one." No code reads a status field. collectPrefixTable skips only names starting with __, and collectPrefixes filters by prefix spelling and engine, never by standard status.

The behavior differs from the claim. A construct BCD lists with prefix-only support and no unprefixed entry gets unprefixedFrom === null, so target becomes Infinity at line 3528 and the entry is emitted with an always-needed window. The minifier then adds a prefixed copy beside any authored occurrence of that base name.

Either read the BCD status and skip non-standard entries, or correct the comment to describe the actual filter.

As per coding guidelines: "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 3570 - 3587, Update the comment
above collectPrefixTable to accurately describe its actual behavior: it excludes
internal names beginning with "__" and includes entries for which
collectPrefixes returns data, without claiming a standard-status filter. Keep
the implementation unchanged unless needed to make the revised comment precise.

Source: Coding guidelines


3444-3446: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trim the new comment blocks to two lines.

Four of the new comment blocks run three to five lines: 3444-3446, 3463-3467, 3484-3487, and 3503-3507. Each states useful non-obvious reasoning, so the content should stay — move the detail into the adjacent JSDoc block, which has no length limit, and keep the leading comment to two lines.

As per coding guidelines: "Keep comments as short as possible, generally one line and no more than two short lines."

Also applies to: 3463-3467, 3484-3487, 3503-3507

🤖 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 3444 - 3446, Shorten the new
leading comment blocks near the BCD browser-id mapping and the corresponding
blocks at the other referenced locations to no more than two lines. Preserve
their non-obvious reasoning by moving the excess detail into each adjacent JSDoc
block.

Source: Coding guidelines


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

Use JSON.stringify for the interpolated names, matching the other literal helpers.

prefixLiteral interpolates name, prefix, and browser directly into "…" with no escaping. Every other literal helper in this file goes through JSON.stringify for the same job — see the POSITION_X_KEYWORDS emission at line 3848 and the FAMILY_LONGHANDS emission at line 3727.

The values are CSS identifiers today, so no quote or backslash reaches the output. The inconsistency is what makes this worth changing: a future BCD key with an unexpected character would emit broken JavaScript into lib/css/data.js rather than failing in the generator.

♻️ Match the file's escaping convention
 const prefixLiteral = (table) =>
 	`new Map([${table
 		.map(([name, prefixes]) => {
 			const body = prefixes
 				.map(([prefix, browsers]) => {
 					const list = browsers
-						.map(([browser, from, to]) => `["${browser}", ${from}, ${to}]`)
+						.map(
+							([browser, from, to]) =>
+								`[${JSON.stringify(browser)}, ${from}, ${to}]`
+						)
 						.join(", ");
-					return `["${prefix}", [${list}]]`;
+					return `[${JSON.stringify(prefix)}, [${list}]]`;
 				})
 				.join(", ");
-			return `["${name}", [${body}]]`;
+			return `[${JSON.stringify(name)}, [${body}]]`;
 		})
 		.join(", ")}])`;
🤖 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 2534 - 2547, Update the
prefixLiteral helper so the interpolated name, prefix, and browser values are
serialized with JSON.stringify instead of manual double-quoted interpolation.
Match the escaping convention used by the other literal helpers while preserving
the generated Map structure and numeric from/to values.

3463-3482: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Derive the engine-to-prefix mapping from BCD's release engine field.

BROWSER_PREFIXES hand-types 13 browser entries. BCD publishes the engine for every release at bcd.browsers[id].releases[version].engine — "Blink", "Gecko", "WebKit", "Presto", "EdgeHTML", "Trident". A table of 6 engines to prefixes, joined against that field, replaces the 13 browser rows and covers the dual listings for edge and opera from the data instead of from the comment.

BCD_TO_BROWSERSLIST at lines 3447-3461 is a different case. No published dataset links BCD ids to browserslist names, and the comment states why BCD-only engines are absent, so the hand-typed map is justified there.

As per path instructions: "Generators must derive tables from published datasets (mdn-data, color-name, vendored webref) rather than hand-typing name lists; a SUPPLEMENT entry needs a stated reason it cannot be derived."

🤖 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 3463 - 3482, Replace the
hand-typed browser entries in BROWSER_PREFIXES with a six-engine-to-prefix
mapping derived from BCD release metadata. Build the browser prefix lookup by
joining each bcd.browsers[id].releases[version].engine value to the
corresponding engine prefixes, preserving the published engine-specific prefixes
and allowing EdgeHTML/Trident and Presto cases to emerge from the data. Leave
BCD_TO_BROWSERSLIST unchanged.

Source: Path instructions

lib/css/syntax.js (1)

5948-5954: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

_neededPrefixes returns null for two opposite meanings, and _prefixRemovable reads the wrong one as removable.

_neededPrefixes returns null when no target needs a prefix (line 5927) and also when browsers is absent (line 5893). At line 5953 _prefixRemovable treats null as removable. So a caller reaching _prefixRemovable without a browser list would strip author prefixes with no target information — silently wrong output CSS.

Every current caller is gated. The declaration path checks environment.browsers at lines 9218-9222. The rule paths run only when _seenPrefixRules !== null, which requires the same check at lines 4665-4671. So this is not reachable today.

The overload is what makes it fragile: the gate lives in the callers, not in the function that depends on it. An explicit check inside _prefixRemovable makes the requirement local.

♻️ Make the precondition local
 const _prefixRemovable = (table, base, prefix, tag, writer) => {
+	const environment = /** `@type` {CssEnvironment | undefined} */ (
+		writer.options.environment
+	);
+	// No target list means no basis to judge a prefix dead; keep it.
+	if (!environment || !environment.browsers) return false;
 	const prefixes = table.get(base);
 	if (prefixes === undefined) return false;
🤖 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 5948 - 5954, Update _prefixRemovable to
explicitly require an available browser list before treating a prefix as
removable; when the required browser information is absent, return false.
Preserve the existing _neededPrefixes handling for cases where browser data
exists, including removing prefixes only when its result confirms the prefix is
unnecessary.
test/configCases/css/minimize-vendor-prefixes/webpack.config.js (1)

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

Shorten the configuration comment to two lines.

The comment spans four lines. Keep the non-obvious reason for the Browserslist target and stable versions.

Suggested revision
-	// A browserslist target so the default minimizer wiring resolves its browser
-	// list and hands it to `cssMinify` — the whole option flow, not the
-	// serializer alone. Exact versions in `.browserslistrc` keep the snapshot
-	// stable as caniuse updates.
+	// A browserslist target lets the default minimizer resolve browser targets.
+	// Exact versions keep the snapshot stable as caniuse updates.

As per coding guidelines, comments under {lib,hot,tooling,test}/**/*.{js,mjs} must be as short as possible and no more than two short lines. As per path instructions, comments under test/** follow the same limit.

🤖 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/configCases/css/minimize-vendor-prefixes/webpack.config.js` around lines
5 - 8, Shorten the comment above the Browserslist target to no more than two
short lines while preserving both points: the target exercises the default
minimizer-to-cssMinify option flow, and exact versions keep snapshots stable as
caniuse updates.

Sources: Coding guidelines, Path instructions

🤖 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 @.changeset/158-css-vendor-prefixes.md:
- Line 5: Shorten the changeset summary to one capitalized imperative sentence
of 80 characters or fewer, preserving that CSS vendor prefixes are added or
removed based on the browserslist target.

In `@lib/config/defaults.js`:
- Around line 2479-2492: Update the browser resolution in the minimizerOptions
path around the browsers variable so worker tasks reuse a stable per-worker
browser list instead of creating a new array for each asset. Preserve the
existing target normalization and Context handling, and ensure the css/syntax
WeakMap caches can retain entries across assets by resolving the list once or
replacing identity-based caching with an equivalent value-based key.

In `@lib/css/syntax.js`:
- Around line 4665-4671: The finally cleanup in grammar() must also release
_seenPrefixRules after each parse. Add it to the existing per-parse module-state
reset alongside the other fields, preserving the current initialization and
minification behavior during parsing.
- Around line 9230-9269: Update the prefix-handling loop to use the property
name emitted by replacement text for merged longhand indices, or skip prefix
processing for those indices. Ensure merged border-radius entries still receive
the required -moz-border-radius prefix while preserving normal handling for
unmerged declarations.

In `@test/CssSyntax.unittest.js`:
- Around line 4409-4413: Rename the test case describing Safari Technology
Preview so it no longer claims “no prefix” and instead reflects that the TP rule
adds the expected -webkit-user-select prefix. Keep the assertion and test
behavior unchanged.

In `@tooling/generate-css-data.js`:
- Around line 3522-3527: Update the unprefixed-version calculation in the
entries loop to select the earliest non-prefixed version independent of BCD
array order, and account for each entry’s version_removed so unprefixed support
applies only within its active version range. Preserve separate unprefixed
windows for re-added entries rather than allowing a later entry to overwrite
earlier boundaries.

---

Nitpick comments:
In `@lib/css/syntax.js`:
- Around line 5948-5954: Update _prefixRemovable to explicitly require an
available browser list before treating a prefix as removable; when the required
browser information is absent, return false. Preserve the existing
_neededPrefixes handling for cases where browser data exists, including removing
prefixes only when its result confirms the prefix is unnecessary.

In `@test/configCases/css/minimize-vendor-prefixes/webpack.config.js`:
- Around line 5-8: Shorten the comment above the Browserslist target to no more
than two short lines while preserving both points: the target exercises the
default minimizer-to-cssMinify option flow, and exact versions keep snapshots
stable as caniuse updates.

In `@test/CssSyntax.unittest.js`:
- Around line 4316-4320: Hoist the identical minify helper from the three
describe blocks into a single shared definition above them in the test module.
Remove each local duplicate and have all three blocks reuse the shared minify
function, preserving its existing SourceProcessor configuration and return
behavior.
- Around line 4462-4468: Add test coverage for prefixed-first ordering in the
rule-level at-rule removal tests near the existing prefixed/unprefixed cases:
place the prefixed `@-webkit-keyframes` rule before its unprefixed `@keyframes` twin
and assert the current streaming behavior, preserving the documented order
dependency. Apply the same coverage to the corresponding test around the
alternate referenced range, without changing implementation behavior.

In `@tooling/generate-css-data.js`:
- Around line 3570-3587: Update the comment above collectPrefixTable to
accurately describe its actual behavior: it excludes internal names beginning
with "__" and includes entries for which collectPrefixes returns data, without
claiming a standard-status filter. Keep the implementation unchanged unless
needed to make the revised comment precise.
- Around line 3444-3446: Shorten the new leading comment blocks near the BCD
browser-id mapping and the corresponding blocks at the other referenced
locations to no more than two lines. Preserve their non-obvious reasoning by
moving the excess detail into each adjacent JSDoc block.
- Around line 2534-2547: Update the prefixLiteral helper so the interpolated
name, prefix, and browser values are serialized with JSON.stringify instead of
manual double-quoted interpolation. Match the escaping convention used by the
other literal helpers while preserving the generated Map structure and numeric
from/to values.
- Around line 3463-3482: Replace the hand-typed browser entries in
BROWSER_PREFIXES with a six-engine-to-prefix mapping derived from BCD release
metadata. Build the browser prefix lookup by joining each
bcd.browsers[id].releases[version].engine value to the corresponding engine
prefixes, preserving the published engine-specific prefixes and allowing
EdgeHTML/Trident and Presto cases to emerge from the data. Leave
BCD_TO_BROWSERSLIST unchanged.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c667df1-e440-4043-9c51-da693a0f0ba3

📥 Commits

Reviewing files that changed from the base of the PR and between 78d0d4c and 1bb4658.

⛔ Files ignored due to path filters (5)
  • lib/css/data.js is excluded by !lib/css/data.js
  • test/configCases/css/minimize-vendor-prefixes/__snapshots__/ConfigCacheTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
  • test/configCases/css/minimize-vendor-prefixes/__snapshots__/ConfigTest.snap is excluded by !**/*.snap, !test/**/__snapshots__/**
  • types.d.ts is excluded by !types.d.ts
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock, !yarn.lock
📒 Files selected for processing (13)
  • .changeset/158-css-vendor-prefixes.md
  • cspell.json
  • lib/config/defaults.js
  • lib/config/target.js
  • lib/css/syntax.js
  • package.json
  • test/CssSyntax.unittest.js
  • test/configCases/css/minimize-vendor-prefixes/.browserslistrc
  • test/configCases/css/minimize-vendor-prefixes/index.js
  • test/configCases/css/minimize-vendor-prefixes/style.css
  • test/configCases/css/minimize-vendor-prefixes/test.config.js
  • test/configCases/css/minimize-vendor-prefixes/webpack.config.js
  • 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)

Comment thread .changeset/158-css-vendor-prefixes.md Resolved
Comment thread lib/config/defaults.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread lib/css/syntax.js Resolved
Comment thread test/CssSyntax.unittest.js Resolved
Comment thread tooling/generate-css-data.js Resolved
…BCD's earliest unprefixed version

A merged box shorthand is stored on one longhand's node, so the node name is
not the property emitted — border-radius went unprefixed for a target needing
-moz-. In the generator, the unprefixed arrival is the earliest support entry
rather than the last read, and one BCD later removed never established it.
Also release the prefix-rule set with the other per-parse state, and key the
browserslist memo on the joined text so a worker's fresh array still hits it.

@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)

9251-9292: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Track complete declarations, not property names.

Lines 9251-9292 treat one existing prefixed property as coverage for every declaration of that property. For -webkit-appearance:auto;appearance:none, a target that requires -webkit- does not receive -webkit-appearance:none because Line 9289 sees -webkit-appearance as present. That target applies auto instead of none.

The same property-only check can remove an authored prefixed declaration with distinct value or cascade behavior. Track normalized declaration text, including value and !important, and preserve declaration order when adding or removing prefixes.

🤖 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 9251 - 9292, Update the declaration tracking
and prefix-removal/addition logic around _printedProperty so coverage is based
on normalized complete declaration text, including value and !important, rather
than property names alone. Ensure -webkit-appearance:auto and appearance:none
are handled independently, and preserve authored declaration order when
inserting required prefixes or removing redundant ones.
🧹 Nitpick comments (1)
tooling/generate-css-data.js (1)

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

Shorten the new comments. Both comments use three lines and repeat behavior expressed by the adjacent code. Keep only the non-obvious reason in no more than two short lines.

  • tooling/generate-css-data.js#L3524-L3526: reduce the BCD ordering explanation to one or two short lines.
  • lib/css/syntax.js#L5832-L5834: reduce the memo-key explanation to one or 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."

🤖 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 3524 - 3526, Shorten the comments
at tooling/generate-css-data.js lines 3524-3526 and lib/css/syntax.js lines
5832-5834 to one or two short lines each, retaining only the non-obvious BCD
ordering and memo-key rationale; remove wording that repeats adjacent code
behavior.

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.

Outside diff comments:
In `@lib/css/syntax.js`:
- Around line 9251-9292: Update the declaration tracking and
prefix-removal/addition logic around _printedProperty so coverage is based on
normalized complete declaration text, including value and !important, rather
than property names alone. Ensure -webkit-appearance:auto and appearance:none
are handled independently, and preserve authored declaration order when
inserting required prefixes or removing redundant ones.

---

Nitpick comments:
In `@tooling/generate-css-data.js`:
- Around line 3524-3526: Shorten the comments at tooling/generate-css-data.js
lines 3524-3526 and lib/css/syntax.js lines 5832-5834 to one or two short lines
each, retaining only the non-obvious BCD ordering and memo-key rationale; remove
wording that repeats adjacent code behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7406e1a9-faeb-4a66-9131-cc4a5169130b

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb4658 and 2318c90.

⛔ Files ignored due to path filters (1)
  • lib/css/data.js is excluded by !lib/css/data.js
📒 Files selected for processing (4)
  • .changeset/158-css-vendor-prefixes.md
  • lib/css/syntax.js
  • test/CssSyntax.unittest.js
  • 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 (2)
  • .changeset/158-css-vendor-prefixes.md
  • test/CssSyntax.unittest.js

@aryanraj45

aryanraj45 commented Aug 10, 2026 •

Copy link
Copy Markdown
Member Author

@alexander-akait Rebased on main. Also fixed the review comments - the border-radius one was a real bug, the merged shorthand never got -moz- because the property was read from the AST name instead of the printed text. Added a test for it.

Can u please take a look and re-run the CI, thanks!

@alexander-akait

Copy link
Copy Markdown
Member

Fixed with a lot of fixes in the main, thanks for start and helping me

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.

2 participants