react / react/react-strict-dom
postcss plugin re-transforms every included file on each rebuild under Turbopack (minutes-long HMR in large projects)
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 3.6k
- Forks
- 206
- PR merge metrics
- No merged PRs in 30d
Description
Summary
In a Next.js 16 app using react-strict-dom/postcss-plugin, every incremental rebuild under Turbopack (the default dev bundler) re-transforms all files matched by the plugin's include globs, not just the changed file. In a large monorepo (~4,000 included source files) this makes a one-line edit take ~80 seconds to rebuild, while the same edit under next dev --webpack rebuilds in ~4 seconds.
Environment
- react-strict-dom: 0.0.55 (postcss-react-strict-dom 0.0.55)
- next: 16.2.11 (Turbopack dev)
- node: 22.x, macOS (M-series)
- postcss.config.js:
react-strict-dom/postcss-pluginwithincludeglobs covering the app + shared workspace packages (~4,000.ts/.tsxfiles),useLayers: true, and the documentedbabelConfigwithreact-strict-dom/babel-preset
Measurements (same machine, same session)
| Scenario | Time |
|---|---|
| Cold compile of one route (Turbopack) | ~50s |
One-line edit to any file matched by include (Turbopack) |
~80s |
Edit to a file NOT matched by include (Turbopack) |
0.35s |
One-line edit, next dev --webpack |
4.4s |
Creating a new untracked file that matches the globs — even one that nothing imports — also triggers the full ~80s rebuild, since the generated CSS has a dir-dependency on the glob roots.
Analysis
The plugin already has an incremental path: postcss-react-strict-dom/src/builder.js keeps a fileModifiedMap of mtimes and skips unchanged files. But that cache lives in the plugin instance's memory:
- Under webpack, Next keeps the PostCSS config module (and the plugin closure) alive across rebuilds, so only the changed file is re-transformed → ~4s HMR.
- Under Turbopack, the PostCSS transform runs in a
turbopack-nodeworker whose module state does not survive the invalidation, sofileModifiedMapis empty on every rebuild and all ~4,000 files are re-parsed and babel-transformed serially in a single worker on every edit.
Profiling during a rebuild shows one Node process (the turbopack-node PostCSS transform) pegged at ~100% CPU for the entire rebuild while everything else idles. A native sample of that process lands almost entirely in Array.prototype.includes via postcss's MapGenerator.previous() (previousMaps.includes(map) per AST node — quadratic when the generated CSS has many nodes with distinct input maps), with the repeated Babel transform pass as the underlying volume of work.
Suggested fixes
- A persistent (disk-backed) cache for the per-file transform results, keyed by path + mtime/content hash (similar to Tailwind's approach), so extraction stays incremental regardless of the host process lifecycle.
- Alternatively/additionally: a note in the Next.js setup docs that large projects should currently prefer
next dev --webpack, since Turbopack defeats the plugin's in-memory cache.
Repro
I can't share the affected monorepo, but the behavior scales with the number of files matched by include: generating a few thousand small components using css.create from react-strict-dom and pointing the plugin's include at them reproduces the per-edit full re-extraction under next dev (Turbopack) vs the fast incremental path under next dev --webpack. Happy to put together a synthetic repro repo if useful.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with postcss-react-strict-dom/src/builder.js and its fileModifiedMap, then reproduce the incremental behavior with a synthetic project containing many matched files under next dev using Turbopack and webpack. Compare cache behavior across rebuilds; done means incremental extraction remains effective across Turbopack invalidations, or the documented webpack workaround is added and verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, next.js, react
- Domain
- build-system, performance, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100