feat(herowars): migrate JSON static imports to HttpClient assets
Replace all TypeScript JSON imports with an HWDataService that loads 6 data files from /assets/files-data/ via HttpClient with shareReplay(1). Update all 9 consumer components to subscribe asynchronously. Remove unused qcm-bpa.json import and dead methods from QcmComponent. Add ADR 0013 documenting the decision.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Migrate HeroWars static JSON imports to HttpClient assets
|
||||
|
||||
- Status: accepted
|
||||
- Date: 2026-04-26
|
||||
|
||||
## Context and Problem Statement
|
||||
|
||||
Six large JSON files (36 KB–3 MB) were statically imported directly into Angular components and services via TypeScript `import` statements. This bundled all the data into the main JavaScript bundle, inflating the initial download regardless of whether the user navigated to the HeroWars section. The largest file (`hw-guild-raids.json`, 3 MB) alone would significantly delay first contentful paint for all users.
|
||||
|
||||
Additionally, a seventh file (`qcm-bpa.json`, 210 KB) was imported but never consumed — the component had switched to a route resolver but the dead import remained.
|
||||
|
||||
## Decision Drivers
|
||||
|
||||
- Static JSON imports are compiled into the bundle — they cannot be lazy-loaded or cached by the browser independently.
|
||||
- Updating the data files required a recompile and redeployment; serving them as assets allows hot-swapping without a rebuild.
|
||||
- The HeroWars section is used by a small subset of users; its data should not penalise all other users' load time.
|
||||
|
||||
## Considered Options
|
||||
|
||||
- Keep static imports
|
||||
- Move JSON to assets and load via `HttpClient`
|
||||
- Fetch data from the API backend
|
||||
|
||||
## Decision Outcome
|
||||
|
||||
Chosen option: "Move JSON to assets and load via HttpClient", because it removes the data from the bundle, enables browser-level HTTP caching, and requires no backend changes. The files are not secret (guild-internal analytics data) so serving them as static assets is appropriate.
|
||||
|
||||
Structure:
|
||||
|
||||
- JSON files moved from `src/files-data/` to `src/assets/files-data/`
|
||||
- `HWDataService` created at `src/app/core/services/herowars/hw-data.service.ts` — exposes one `readonly` observable per file, each piped through `shareReplay(1)` so the HTTP request fires at most once per app lifecycle
|
||||
- `HWClanService.loadClan()` and `HWMemberService.loadMembers()` converted from synchronous return values to `Observable<T>`
|
||||
- All consumer components inject `HWDataService` and subscribe in `ngOnInit()`; template-called methods that previously accessed `guildWarSlots.slots` inline now read from a `_slots` class property populated in the subscribe callback
|
||||
- Unused `import data from 'src/qcm-bpa.json'` and two dead import-helper methods removed from `qcm.component.ts`
|
||||
|
||||
### Positive Consequences
|
||||
|
||||
- HeroWars JSON (~4 MB total) no longer shipped in the initial bundle.
|
||||
- Each JSON file is independently cacheable by the browser with standard HTTP cache headers.
|
||||
- Data files can be updated without recompiling the Angular application.
|
||||
- `shareReplay(1)` ensures a single HTTP request per session even when multiple components subscribe to the same observable.
|
||||
|
||||
### Negative Consequences
|
||||
|
||||
- Components now initialize asynchronously — there is a brief render before data arrives (consistent with the rest of the app's HTTP-driven components).
|
||||
- `Object.entries()` on `any`-typed HTTP responses requires explicit `Record<string, T>` casts to satisfy strict TypeScript, adding minor verbosity.
|
||||
|
||||
## Pros and Cons of the Options
|
||||
|
||||
### Keep static imports
|
||||
|
||||
- Good, because synchronous — no async lifecycle complexity.
|
||||
- Bad, because adds up to 4 MB to the initial bundle.
|
||||
- Bad, because data updates require a full rebuild and redeployment.
|
||||
|
||||
### Move JSON to assets and load via HttpClient
|
||||
|
||||
- Good, because removes data from the bundle entirely.
|
||||
- Good, because browser-cacheable independently of the app JS.
|
||||
- Good, because hot-swappable without a recompile.
|
||||
- Bad, because converts synchronous service methods to observables, requiring component updates.
|
||||
|
||||
### Fetch from API backend
|
||||
|
||||
- Good, because data could be managed dynamically via the admin interface.
|
||||
- Bad, because requires significant backend work (new endpoints, data model) for data that is currently managed as flat files.
|
||||
- Bad, because adds latency and a failure mode not present with local assets.
|
||||
Reference in New Issue
Block a user