Skip to content

feat(init): detect css modules and auto-install compatibility workarounds - #3059

Open
NriotHrreion wants to merge 1 commit into
cloudflare:mainfrom
NriotHrreion:feature/vinext-init-css-modules-support
Open

feat(init): detect css modules and auto-install compatibility workarounds#3059
NriotHrreion wants to merge 1 commit into
cloudflare:mainfrom
NriotHrreion:feature/vinext-init-css-modules-support

Conversation

@NriotHrreion

@NriotHrreion NriotHrreion commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Closes #2992

Overview

Vite scopes CSS Modules before running user PostCSS plugins, which differs from Next.js and can silently break transformations that depend on original selectors, such as postcss-extend-rule. vite-css-modules restores the expected processing order, but its default class-name hashing can produce different results across vinext's separate server and client environments (see #2992 (comment)).

This PR makes CSS Modules projects work consistently by automatically setting up vite-css-modules and deterministic, project-relative class names, preserving PostCSS behavior while preventing server/client class-name mismatches in development and production builds.

What changed

  • During vinext init, scan the original Next.js project folder for css modules, if there is, enable the css modules compatibility setup path.
  • vite-css-modules will be installed as a devDependency.
  • vite-css-modules will be added to vite config as a plugin, along with the generateScopedName() config.
  • Edge cases of creating and modifying vite config file are considered and added to the tests.

Verification

Question

Should we add an option (maybe a cli flag) to let developers decide whether to apply the css modules compatibility setup?

@pkg-pr-new

pkg-pr-new Bot commented Aug 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3059
npm i https://pkg.pr.new/create-vinext-app@3059
npm i https://pkg.pr.new/@vinext/types@3059
npm i https://pkg.pr.new/vinext@3059

commit: 1114197

@github-actions

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 1114197 against base 20fdac4 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 141.4 KB 141.4 KB ⚫ -0.0%
Client entry size (gzip) vinext 128.8 KB 128.8 KB ⚫ -0.0%
Dev server cold start vinext 2.93 s 2.93 s ⚫ +0.1%
Production build time vinext 3.12 s 3.08 s ⚫ -1.2%
RSC entry closure size (gzip) vinext 115.6 KB 115.6 KB ⚫ +0.0%
Server bundle size (gzip) vinext 196.8 KB 196.8 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1114197494

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1543 to +1546
const plugins = findProperty(config, "plugins");
if (!plugins) {
const indent = objectPropertyIndent(config, code);
insertObjectProperty(output, config, `${indent}plugins: [${expression}],`, code, true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve plugins supplied through config spreads

For a Node-target CSS Modules project whose config is composed as export default { ...sharedConfig }, findProperty sees no direct plugins property, so this branch appends plugins: [patchCssModules()] after the spread. That replaces rather than extends sharedConfig.plugins, potentially removing vinext, React, and other required plugins from the effective Vite config. Detect and merge spread-provided plugins, or reject this ambiguous shape instead of silently overwriting them.

Useful? React with 👍 / 👎.

Comment on lines +605 to +609
} else if (hasCssModules && existingViteConfigPath) {
updateViteConfigForCssModules(
existingViteConfigPath,
fs.readFileSync(existingViteConfigPath, "utf-8"),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Let --force bypass CSS config validation

When --platform=node --force is used in a CSS Modules project, this preflight still parses and validates the existing config before setupNodePlatform can replace it. Thus an unsupported existing shape such as css: getCss() throws even though --force is specifically the recovery path for overwriting a Node-target Vite config; gate this validation on !options.force so replacement can proceed.

Useful? React with 👍 / 👎.

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: @extend (postcss-extend-rule) silently dropped — CSS-Modules plugin runs before user PostCSS plugins

1 participant