fix(bundle-budget): emit the stats fields the nightly gate reads - #1283
Merged
Conversation
`pnpm build:stats` runs `webpack --json`, and webpack-cli serializes that
dump with `compiler.options.stats`. That object sets `all: false`, which
overrides its own `preset`, so the JSON carried only `{time, errors,
warnings}` and check-bundle-budget.mjs exited 2 with "stats has no `main`
entrypoint" — the nightly job failed on its first scheduled run.
Widen stats for `--json` dumps only, to the fields the budget script
reads: entrypoints, assets, chunks with their modules and origins, plus
nested, dependent and cached modules, which `all: false` would otherwise
collapse into placeholders or drop on a warm filesystem cache. Console
output for ordinary builds is unchanged. Module `source` stays excluded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The
Frontend (production bundle budget)job added toNightly full checksin #1249 failed on its first scheduled run (run 33930333000):The production build itself succeeded.
pnpm build:statsrunswebpack --json build/stats.json, and webpack-cli serializes that dump with the config's own stats object (webpack-cli/lib/webpack-cli.js:stats.toJson(compiler.options.stats)).config/webpack.config.jssetsstats.all: falseto keep console output terse, andalloverrides its siblingpreset, so the JSON carried only{time, errors, warnings}.scripts/quality/check-bundle-budget.mjsexited 2 on the missing entrypoint;stats.assets,chunk.modulesandchunk.originswere absent for the same reason. The gate has never produced a measurement, andpnpm analyzewas being handed the same near-empty dump.Solution
Split the stats object on
argv.json, which onlybuild:statsandanalyzeset. JSON dumps get exactly the fields the budget script reads —entrypoints,assets,chunks,chunkModules,chunkOrigins,nestedModules— plusdependentModulesandcachedModules. Those last two matter more than they look: withall: falsewebpack collapses dependent modules into"N dependent modules"placeholders and drops every module the filesystem cache served, which both under-counts the boot graph (2,610 real src modules were reported as 27) and makes the number depend on whether the cache was warm.Everything else stays off, so module
sourceis still excluded andbuild/stats.jsonlands at ~60 MB rather than gigabytes. Ordinary builds keep the identical terse console block — every other caller (build,build:release,build:mobile-native,scripts/dev/webpack-server.js, the light-config tests) passes anargvwithoutjson.Resulting invariant: a
--jsonbuild emits an entrypoint, per-chunk modules and origins, and an untruncated module list independent of cache state. Both branches are asserted inscripts/dev/webpack-config-light.test.cjs.Potential risks
develop(2daa781) the boot bundle is 6.52 MB JS vs the 6.39 MB budget (+2.0%);maxSrcModulespasses at 2,610 / 2,850. At 947baff, the merge that set the budget, the same script measures 5.93 MB / 37 chunks / 2,585 modules — matching the 37 chunks recorded in the script's header, so the budget was sound when written and the boot graph grew ~604 KB in a day. See Follow-up; deciding whether to shrink the graph or ratchet the number is a separate change and does not belong in this PR.build/stats.jsongrows from ~19 KB to ~60 MB in that job's workspace. It is transient and not uploaded as an artifact.pnpm analyzenow receives these fields too. It was previously getting the empty dump, so this can only improve it, but the analyzer output is unverified here.pnpm scripts:testis not wired into CI or any hook, so the new assertions run only when someone runs that suite by hand.git worktreewith hooks bypassed (core.hooksPath=/dev/null; the worktree has no.husky/_/husky.sh), so thePre-commit hook ran.trailer is absent and lint-staged did not run. The equivalent checks were run by hand — see Verification.Verification
Run in a clean
git worktreeoforigin/developwithnode_modulessymlinked from the main checkout.--jsonoutput keys weretime, errors, warnings;entrypoints,assetsandchunksall missing. Adding the fields in this diff restored every one.NODE_OPTIONS=--max-old-space-size=6144 npx webpack --config config/webpack.config.js --mode production --json build/stats.jsonat 2daa781 → exit 0,build/stats.json60,850,713 bytes.node scripts/quality/check-bundle-budget.mjs→ runs to completion, exit 1:Boot bundle (39 chunks) / JS 6.52 MB budget 6.39 MB / src JS mods 2610 budget 2850, area breakdown led byengines/ChatPanel421,engines/SessionCore185,features/Org2Cloud161 — the shape the script's header describes. Before this change the same command exited 2 without measuring anything.Boot bundle (37 chunks) / JS 5.93 MB / src JS mods 2585→ passes. This is what establishes that the harness is fixed and the remaining failure is real growth.node --test scripts/dev/webpack-config-light.test.cjs→ 5 pass, 0 fail (3 existing + 2 new).node --test scripts/dev/*.test.cjs→ 45 pass, 2 fail. Both failures are inscripts/dev/startup-watchdog.test.cjs, which asserts onsrc-tauri/src/lib.rstext; they fail identically on unmodified 947baff, so they are pre-existing and unrelated.npx prettier --checkon both changed files → clean. ESLint is not applicable:package.json#eslintConfigignorePatterns(/*,!/src) ignores everything outsidesrc/, andscripts/ci/select-lint-targets.cjsfilters CI's changed-file lint tosrc/-prefixed paths, so neither file reaches ESLint.vitest,tsc/tsgo, and Rust checks. Nosrc/or Rust file is touched; CI covers all three on this PR.Follow-up
Not part of this change, but the diff that explains the 2.0% overage, comparing boot chunks at 947baff → 2daa781:
vendors+576 KB, plus two newly shared chunks (common, and one carrying./src/mobileRemoteEntry.tsxorigins) worth +634 KB, againstmain−193 KB. Only 25 src modules became newly reachable (2,585 → 2,610), so this is almost entirely re-splitting, not new application code: #1271 added a secondmobileentrypoint toentry, and splitChunks now hoists code shared by the two entries into chunks the desktop shell also loads. Worth deciding whether the mobile entry should share the desktopvendorschunk before ratchetingconfig/bundle-budget.json.🤖 Generated with Claude Code