Skip to content

chore(examples): add bundle analysis and blocking size budgets - #1145

Open
redfish4ktc wants to merge 4 commits into
mainfrom
chore/improve_build_of_examples
Open

chore(examples): add bundle analysis and blocking size budgets#1145
redfish4ktc wants to merge 4 commits into
mainfrom
chore/improve_build_of_examples

Conversation

@redfish4ktc

@redfish4ktc redfish4ktc commented Aug 18, 2026

Copy link
Copy Markdown
Member

Why

The bundled example packages had no way to tell what ends up in their bundle, and no guard against it growing.

The Vite examples declared a chunkSizeWarningLimit, but it only makes Vite log a warning and the build still exits 0, so a bundle regression showed up as a single line in a CI log that nobody reads (upstream request: vitejs/vite#18496). The webpack examples had no budget at all.

What

Bundle analysis, opt-in, in the six bundled examples. Rsdoctor for the three webpack examples, vite-bundle-analyzer for the three Vite ones, since Rsdoctor supports only webpack and Rspack. Both are enabled by a dedicated npm run build:analyze script, which sets ANALYZE=true through cross-env so the command also works in Windows shells. The regular npm run build is untouched: no analyzer, no report server, no source map. A source map is generated for the analyze run only, hidden-source-map for webpack and sourcemap: 'hidden' for Vite, so the analyzed bundle stays byte for byte the one the regular build produces, content hash included; Rsdoctor needs it to attribute bytes to individual modules.

The production build now fails when a bundle grows. The webpack examples get a performance budget with hints: 'error', in production only, since development bundles are not minified and would break npm run dev. Vite cannot do this on its own, so the examples pass their limit to a shared plugin, scripts/vite/chunk-size-limit.mjs, which fails the build naming the chunk and both sizes. Each limit is declared once per example and feeds both chunkSizeWarningLimit and the plugin, so the warning and the error cannot drift apart.

Each value is the smallest one that passes, that is the current size rounded up to the next kB. The intent is to follow the size evolution rather than to leave room to grow into, so the incidental headroom is accepted; the convention is recorded in .claude/rules/tooling/bundle-size-budgets.md.

--fail-at-end in scripts/build-all-examples.bash, used by the CI. Once a build can fail on size, the first failure would abort the script and hide both the other examples and the size table, so getting the full picture would take one CI run per failing example. With the option, every example is built, the file listing, the markdown table and the CSV are still printed, and the failures are reported after them. The default behavior is unchanged: without the option the script still stops at the first failing build.

Shared Vite configuration. The codeSplitting group that isolates @maxgraph/core in a dedicated maxgraph chunk was copy pasted in the three Vite examples; it now lives in scripts/vite/maxgraph-chunk.mjs next to the size check it feeds. The three vite.config.js are identical apart from their limit, and the three webpack.config.js apart from their budget.

Dependabot. New vite group for vite and vite-*, and @rsdoctor/* added to the existing webpack group, so those libraries move together across the examples. @storybook/html-vite is deliberately left in the storybook group, which owns the Vite version Storybook builds against.

Sizes and budgets

Example current budget
js-example 466,905 B asset, 472,414 B entrypoint 467,000 / 473,000
js-example-selected-features 384,964 B asset, 390,473 B entrypoint 385,000 / 391,000
js-example-without-defaults 239,112 B asset, 240,095 B entrypoint 240,000 / 241,000
ts-example 428,747 B chunk 429 kB
ts-example-selected-features 361,547 B chunk 362 kB
ts-example-without-defaults 220,859 B chunk 221 kB

No bundle size changed in this PR. The js-example-without-defaults budget was initially calibrated against a stale packages/core/lib; rebuilding core brings that bundle to 239,112 B, and the budget follows.

Decisions worth flagging

  • The analyzer and the size guard are never registered together in the Vite examples. vite-bundle-analyzer is a post plugin, so the guard's error aborted the build before any report was written, exactly the case where the report is needed to find out what grew. npm run build, which the CI runs, remains the command that enforces the limit.
  • --list-size-only --fail-at-end is a documented no-op, not an error: nothing is built, so nothing can fail, and a caller passing flags generically should not be rejected for a harmless combination.
  • The artifact upload now runs with if: ${{ !cancelled() }}. Skipping it on failure would defeat the purpose of --fail-at-end, since the dist of the examples that did build is what one wants to inspect. This does not weaken the gate: the job still fails, so the jobs depending on it, the release included, do not run.
  • A failed Vite build leaves no dist, so a failing example disappears from the size table and the CSV instead of showing a stale number.
  • Budgets are tight by design, between 36 B and about 900 B of headroom. A bundler patch bump can therefore turn a build red; the fix is to check the increase is intended and update the value in the same commit.

Validation

  • ./scripts/build-all-examples.bash and ./scripts/build-all-examples.bash --fail-at-end: exit 0, the six examples below their limits, no webpack performance warning and no Vite chunk warning.
  • Guard proven blocking: with a limit lowered to 10 kB, RolldownError: Chunk "assets/maxgraph-Be5ReXNy.js" is 361.55 kB, above the 10 kB limit. and exit 1.
  • --fail-at-end proven: with two limits lowered, both failures are listed after the size table, the third example still builds, exit code 1.
  • Analyze runs verified on both bundlers, report reachable over HTTP, and the emitted bundles unchanged to the byte with identical content hashes.
  • The shared Vite module resolves from the three example packages, and the extraction is a pure refactoring: same chunk sizes and same content hashes as before.
  • npm run lint clean. Note it only covers **/*.ts, so the two new .mjs files are outside its scope; they were linted explicitly.

Summary by CodeRabbit

  • New Features

    • Added local production bundle analysis for Webpack and Vite examples.
    • Added production bundle-size checks that fail builds when configured limits are exceeded.
    • Improved dedicated maxgraph bundle generation.
    • Build scripts now process remaining examples, report failures, and summarize results.
  • Documentation

    • Added guidance for bundle analysis, size budgets, troubleshooting, and updating limits.
  • Chores

    • Improved dependency grouping and build artifact handling in automation.

Every bundled example can now inspect what ends up in its bundle: Rsdoctor for the webpack ones, vite-bundle-analyzer for
the Vite ones. Both are opt-in through 'npm run build:analyze' and never affect the regular build.

The production build now fails when a bundle grows, with webpack 'performance' budgets and, for Vite, a shared plugin,
since chunkSizeWarningLimit only logs a warning and lets the build succeed. Each limit is the smallest value that passes,
the current size rounded up to the next kB, so the budgets track the size evolution. The convention is recorded in
.claude/rules/tooling/bundle-size-budgets.md.

scripts/build-all-examples.bash gains --fail-at-end, used by the CI: a single run shows every example, the size table,
then the failures.

Dependabot groups the vite and the rsdoctor updates, so those libraries stay consistent across the examples.
@redfish4ktc redfish4ktc added the chore Build, CI/CD or repository tasks (issues/PR maintenance, environments, ...) label Aug 18, 2026
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca948e44-2537-4d64-9de7-e153a34ed75b

📥 Commits

Reviewing files that changed from the base of the PR and between 68c733a and 8cce93f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • packages/js-example-selected-features/webpack.config.js
  • packages/js-example-without-defaults/webpack.config.js
  • packages/js-example/webpack.config.js
  • packages/ts-example-selected-features/vite.config.js
  • packages/ts-example-without-defaults/vite.config.js
  • packages/ts-example/vite.config.js
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/js-example-without-defaults/webpack.config.js
  • packages/js-example/webpack.config.js
  • packages/ts-example/vite.config.js
  • packages/js-example-selected-features/webpack.config.js
  • packages/ts-example-without-defaults/vite.config.js
  • packages/ts-example-selected-features/vite.config.js

Included review availability: Your plan includes up to 4 reviews per rolling hour; 3 remain after this review.


Walkthrough

Changes

The example packages now support production bundle analysis with Rsdoctor or vite-bundle-analyzer. Webpack enforces asset and entrypoint budgets. Vite enforces chunk-size limits through a shared plugin. Build scripts can report all failed examples after completing the build.

Bundle analysis and size enforcement

Layer / File(s) Summary
Shared Vite chunk utilities
scripts/vite/*
Added chunk-size enforcement and @maxgraph/core code-splitting utilities.
Webpack analysis and production budgets
packages/js-example*/README.md, packages/js-example*/package.json, packages/js-example*/webpack.config.js
Added Rsdoctor analysis commands, conditional plugin wiring, hidden source maps, and production size limits.
Vite example integration
packages/ts-example*/README.md, packages/ts-example*/package.json, packages/ts-example*/vite.config.js
Added analyzer commands, shared code splitting, production chunk-size enforcement, and configured limits.
Build workflow and budget documentation
scripts/build-all-examples.bash, .github/workflows/*, .claude/rules/tooling/*, CLAUDE.md, .github/dependabot.yml
Added fail-at-end build reporting, Bash 3-compatible iteration, bundle-budget guidance, documentation links, and dependency groups.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 8cce9

This PR adds opt-in bundle analysis and production size-budget enforcement without changing regular build output; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant BuildExamples
  participant ExampleBuild
  participant SizeGuard
  participant ArtifactUpload
  BuildExamples->>ExampleBuild: build each example with --fail-at-end
  ExampleBuild->>SizeGuard: enforce Webpack or Vite budget
  SizeGuard-->>ExampleBuild: success or size-limit failure
  ExampleBuild-->>BuildExamples: record example result
  BuildExamples->>ArtifactUpload: upload completed artifacts unless cancelled
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: bundle analysis and blocking size budgets for examples.
Description check ✅ Passed The description provides detailed rationale, implementation details, budget data, decisions, and validation results, but omits the template checklist sections.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f189e624-c711-4fb2-9850-e68842af414d

📥 Commits

Reviewing files that changed from the base of the PR and between 255ad00 and 68c733a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (25)
  • .claude/rules/tooling/bundle-size-budgets.md
  • .github/dependabot.yml
  • .github/workflows/_reusable_build_examples.yml
  • CLAUDE.md
  • packages/js-example-selected-features/README.md
  • packages/js-example-selected-features/package.json
  • packages/js-example-selected-features/webpack.config.js
  • packages/js-example-without-defaults/README.md
  • packages/js-example-without-defaults/package.json
  • packages/js-example-without-defaults/webpack.config.js
  • packages/js-example/README.md
  • packages/js-example/package.json
  • packages/js-example/webpack.config.js
  • packages/ts-example-selected-features/README.md
  • packages/ts-example-selected-features/package.json
  • packages/ts-example-selected-features/vite.config.js
  • packages/ts-example-without-defaults/README.md
  • packages/ts-example-without-defaults/package.json
  • packages/ts-example-without-defaults/vite.config.js
  • packages/ts-example/README.md
  • packages/ts-example/package.json
  • packages/ts-example/vite.config.js
  • scripts/build-all-examples.bash
  • scripts/vite/chunk-size-limit.mjs
  • scripts/vite/maxgraph-chunk.mjs

Included review availability: Your plan includes up to 4 reviews per rolling hour; 3 remain after this review.

Comment thread packages/js-example-selected-features/webpack.config.js Outdated
Comment thread packages/ts-example-selected-features/vite.config.js
redfish4ktc and others added 3 commits August 18, 2026 15:26
… runs

'build:analyze' builds in production mode, so the performance hints stayed set to 'error' and an oversized bundle made
the compilation report a size error during a run whose only purpose is to explain that very size.

The report itself was never lost, Rsdoctor still wrote its payload and served it, but the run reported a failure and
would have exited non-zero without the report server holding the process open. The Vite examples already skip their
guard when analyzing, so this also aligns the two bundlers.

'npm run build', which the CI runs, remains the command that enforces the budget.

Verified with a budget forced down to 10 kB: the analyze run now reports no size error and still serves its report,
while the plain build still exits 1.
The ESLint configuration declares no Node environment for the JavaScript configuration files, so 'process.env.ANALYZE'
was reported as no-undef. Importing process from 'node:process' makes the dependency explicit, which is also what the
shared chunk size plugin does for Buffer.

Note that 'npm run lint' only covers '**/*.ts', so these files are outside its scope and the error only surfaces in
tooling that lints them directly.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
9.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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

Labels

chore Build, CI/CD or repository tasks (issues/PR maintenance, environments, ...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant