72 lines
2.9 KiB
Markdown
72 lines
2.9 KiB
Markdown
# WebUI Loading And Bundle Budgets
|
|
|
|
The Core WebUI host owns the loading boundary for installed module packages.
|
|
Vite discovers configured packages at build time, but emits an asynchronous
|
|
loader for each package's `src/module.ts` contribution descriptor. At runtime,
|
|
Core imports only descriptors whose backend manifests are enabled and identify
|
|
the matching `frontend.package_name`.
|
|
|
|
The direct descriptor entry is intentional. A package root may re-export pages
|
|
for consumers; importing that barrel as module wiring can cause those pages to
|
|
be evaluated before navigation. Route pages and substantial panels should use
|
|
`React.lazy`, and Core wraps routes in the shared loading/error boundary.
|
|
|
|
## Enforced Budgets
|
|
|
|
`webui/bundle-budget.json` contains the production limits:
|
|
|
|
| Measurement | Raw limit | Gzip limit |
|
|
| --- | ---: | ---: |
|
|
| Initial JavaScript static import closure | 512 KiB | 160 KiB |
|
|
| Largest individual asynchronous JavaScript chunk | 384 KiB | 110 KiB |
|
|
|
|
`npm run build` writes a Vite manifest, measures the entry and its recursive
|
|
static imports, writes `dist/bundle-metrics.json`, and fails when either budget
|
|
is exceeded. `npm run test:module-permutations` applies the same gate to every
|
|
permutation and records the collected results in
|
|
`dist/module-permutation-bundle-metrics.json`. In CI, each result is also added
|
|
to the step summary.
|
|
|
|
Budgets are limits, not targets. A change that approaches a limit should add a
|
|
new lazy boundary or remove unnecessary entry code instead of raising the
|
|
limit without measurement and review.
|
|
|
|
## 2026-07-30 Baseline
|
|
|
|
Measurements use the same full-product source tree and Node 22 runtime. The
|
|
post-change build additionally includes the Search module in the default and
|
|
full-product sets.
|
|
|
|
| Initial-load measurement | Before | After | Reduction |
|
|
| --- | ---: | ---: | ---: |
|
|
| JavaScript assets in initial static closure | 1 | 1 | 0% |
|
|
| Raw JavaScript | 1,387,043 B | 453,769 B | 67.3% |
|
|
| Gzip level 9 | 364,767 B | 141,725 B | 61.1% |
|
|
| Brotli quality 11 | 254,797 B | 106,701 B | 58.1% |
|
|
| Parse proxy median | 18.776 ms | 7.750 ms | 58.7% |
|
|
| Parse proxy p95 | 21.980 ms | 8.739 ms | 60.2% |
|
|
|
|
The parse proxy constructs a fresh `node:vm` `SourceTextModule` from the entry
|
|
source 30 times with a randomized source marker. It is useful for a controlled
|
|
before/after comparison, but is not enforced in CI because absolute timings
|
|
vary across runners. Transfer budgets use deterministic raw and gzip byte
|
|
counts.
|
|
|
|
The first budgeted full-product build reported:
|
|
|
|
- initial JavaScript: 453,769 B raw / 141,725 B gzip;
|
|
- largest async chunk: `CampaignWorkspace`, 353,724 B raw / 98,142 B gzip.
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core/webui
|
|
npm run build
|
|
npm run check:bundle-budget
|
|
npm run test:module-permutations
|
|
```
|
|
|
|
The build gate also catches accidental eager imports: a page pulled into the
|
|
entry closure consumes the initial budget, while an oversized page or module
|
|
descriptor consumes the asynchronous chunk budget.
|