Follow-up to #4571 / PR #4640, which shed the 5 weight-bearing side-effectful services (economic/market/aviation/trade/consumer-prices) from eager main.js via barrel surgery. The mechanism is proven and guarded; this issue applies it to the remaining tail.
The tail
src/services/index.ts still export *'s ~20 more services that run a module-load side effect (new XServiceClient() / createCircuitBreaker() at top level). By side-effect count: supply-chain (4), conflict (5), infrastructure (5), research (4), climate (4), prediction (2), maritime (2), unrest (2), and ~12 more with 2 each. Individually small (diminishing returns vs the heavy 5), but each still forces its client init into eager parse.
Recipe (proven in #4640)
Per service, measure-gated:
- Remove
export * from './<svc>' from src/services/index.ts.
- Repoint its consumers — panels import
@/services/<svc> directly (already lazy); dynamic-import any data-loader.ts fetchers inside their viewport-gated method(s). For a big method with multiple try blocks, put the import at method scope and guard it (try/early-return + console.warn) if any caller is unguarded.
- Add the service name to the
DEFERRED list in tests/services-barrel-eager-guard.test.mts (already guards both export * AND named re-exports).
- Measure-gate:
VITE_VARIANT=full vite build --sourcemap → byte-attribute the service = 0 in main.js.
The circuit-breaker registry (src/utils/circuit-breaker.ts:468) degrades gracefully on a missing breaker, so lazy registration is safe as long as no eager path reads that service's breaker by name before first load. Grep getCircuitBreakerCooldownInfo/isCircuitBreakerOnCooldown per service before deferring (economic's 'FRED Batch' was the only such lookup in the heavy 5).
Low priority — the boot-parse win per tail service is small (~1-2KB min each). Batch a few per PR.
Follow-up to #4571 / PR #4640, which shed the 5 weight-bearing side-effectful services (economic/market/aviation/trade/consumer-prices) from eager
main.jsvia barrel surgery. The mechanism is proven and guarded; this issue applies it to the remaining tail.The tail
src/services/index.tsstillexport *'s ~20 more services that run a module-load side effect (new XServiceClient()/createCircuitBreaker()at top level). By side-effect count: supply-chain (4), conflict (5), infrastructure (5), research (4), climate (4), prediction (2), maritime (2), unrest (2), and ~12 more with 2 each. Individually small (diminishing returns vs the heavy 5), but each still forces its client init into eager parse.Recipe (proven in #4640)
Per service, measure-gated:
export * from './<svc>'fromsrc/services/index.ts.@/services/<svc>directly (already lazy); dynamic-import anydata-loader.tsfetchers inside their viewport-gated method(s). For a big method with multipletryblocks, put the import at method scope and guard it (try/early-return +console.warn) if any caller is unguarded.DEFERREDlist intests/services-barrel-eager-guard.test.mts(already guards bothexport *AND named re-exports).VITE_VARIANT=full vite build --sourcemap→ byte-attribute the service = 0 inmain.js.#3242 note
The circuit-breaker registry (
src/utils/circuit-breaker.ts:468) degrades gracefully on a missing breaker, so lazy registration is safe as long as no eager path reads that service's breaker by name before first load. GrepgetCircuitBreakerCooldownInfo/isCircuitBreakerOnCooldownper service before deferring (economic's 'FRED Batch' was the only such lookup in the heavy 5).Low priority — the boot-parse win per tail service is small (~1-2KB min each). Batch a few per PR.