# 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` - 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` 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.