Skip to content

fix(css): stabilize CSS module scoped name hash across queries (fix #22957) - #23371

Open
santusht06 wants to merge 2 commits into
vitejs:mainfrom
santusht06:fix/css-modules-query-scoped-name-22957
Open

fix(css): stabilize CSS module scoped name hash across queries (fix #22957)#23371
santusht06 wants to merge 2 commits into
vitejs:mainfrom
santusht06:fix/css-modules-query-scoped-name-22957

Conversation

@santusht06

@santusht06 santusht06 commented Aug 26, 2026

Copy link
Copy Markdown

Description

Fixes #22957.

When CSS Modules are imported with queries (e.g. ?inline or ?inline&used as used by Nuxt's SSR styles feature), PostCSS's generic-names and LightningCSS derive the CSS module hash from the file path passed to their transform options.

Previously, runPostCSS passed from: removeDirectQuery(id) to PostCSS. While general PostCSS plugins intentionally inspect query parameters in atRule.source.input.from, postcss-modules delegates string patterns to generic-names which hashes the full path containing queries like ?inline or ?inline&used. Consequently, importing the same CSS module file normally vs with a query generated mismatched scoped class names within the same build (e.g. _SGzINF8r vs _ZhC-jWQM), breaking SSR inlining and hydration.

Solution

  • In compilePostCSS, wrap generateScopedName (both string patterns and custom functions) so cleanUrl(filename) is passed to the scoping generator while preserving source.input.from for user PostCSS plugins.
  • In compileLightningCSS, pass cleanUrl(filename) for CSS module entries.
  • Updated unit tests in packages/vite/src/node/__tests__/plugins/css.spec.ts ensuring scoped class names remain identical across ?direct, ?inline, and ?inline&used queries for both PostCSS and LightningCSS.

Validation

  • pnpm vitest run packages/vite/src/node/__tests__/plugins/css.spec.ts (50/50 passed)
  • pnpm run test-serve css (137/137 passed)
  • pnpm run test-build css (149/149 passed)
  • pnpm run typecheck (0 errors)
  • pnpm run lint (0 errors)
  • Tested against the minimal reproduction repository (both normal and ?inline imports now produce matching scoped names).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSS Modules: string generateScopedName pattern produces different class names for the same file when imported with a query (e.g. ?inline)

1 participant