postcss plugin re-transforms every included file on each rebuild under Turbopack (minutes-long HMR in large projects)
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- javascript, next.js, react
調査の方向性
postcss-react-strict-dom/src/builder.js とその fileModifiedMap から始め、次に、Turbopack と webpack を使う next dev の下で、多数の一致するファイルを含む合成プロジェクトによってインクリメンタルな動作を再現します。再ビルド間のキャッシュ動作を比較します。Turbopack の無効化後もインクリメンタル抽出が有効であり続けるか、文書化された webpack の回避策が追加され、検証されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
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.
- 主要言語
- JavaScript
- スター
- 3.6k
- フォーク
- 208
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
react/react-strict-dom のほかの issue
-
Outline styles aren't parsed in React Native対応中かも @hoangvvo が 148 日前に担当しました。 オープンbug
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
react/react-strict-dom#467 · コメント 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
react/react-strict-dom#465 · コメント 2 件 ·
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 35/100
react/react-strict-dom#505 · リアクション 2 件 ·
-
Button remains unclickable after disabled state changes対応中かも @MoOx が 131 日前に担当しました。 オープンbug
難易度 3/5 1〜2日 初心者へのやさしさ 62/100
react/react-strict-dom#491 · コメント 4 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 45/100
react/react-strict-dom#482 · コメント 1 件 ·
react/react-strict-dom の issue をすべて見る
似ている issue
-
bug confirmed perf
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
videojs/video.js#9400 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
agent/scanner bug hive/hosted-available-lke648397-260827-5n31
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
rescript-lang/rescript#8765 ·
メンテナーはふだん 1 日以内に返信
-
feedback simulation workshop
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
githubnext/gh-aw-workshop#4417 ·
メンテナーはふだん 1 日以内に返信
-
[Good First Issue]: Add unit tests for NetworkVersionInfo対応中かも @attilayener が今日担当しました。 オープンGood First Issue hacktoberfest
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
hiero-ledger/hiero-sdk-js#4489 ·
メンテナーはふだん 1 日以内に返信