# 2026-07-18 — P2-3 role-aware lazy loading ## Scope Closes P2-3. Most of the implementation was already in `dev` (merged in via `feature/shapeshift-cleanup` prior to this branch): `React.lazy()` for all 12 role groups, `}>`, 12 barrel files, `vite.config.ts` `manualChunks`, `build:analyze` script, `Nav.tsx` hover pre-fetch, and the 4 Playwright specs. This PR: 1. **Fixes a pre-existing JSX bug** in `client/src/pages/admin/HRManagement.tsx` where a previous modal migration had `` at the end of the "Add Applicant Modal" instead of ``. The vite build was failing because of it. Now closes with ``. 2. Ships the missing operator + reviewer doc at **`docs/PERF.md`**. ## Why the build was broken before The HRManagement.tsx migration had a leftover structural error around line 2002. Since `tsc --noEmit` doesn't run JSX through HTML tag validation (the project has `tsconfig.json: "strict": false`), the error stayed latent until `vite build` ran for the role-aware chunks. The vite build errors were: ``` src/pages/admin/HRManagement.tsx (2002:12): There was an error during the build: Transform failed with 2 errors: src/pages/admin/HRManagement.tsx:2002:12: ERROR: Unexpected closing "div" tag does not match opening "ModalBody" tag src/pages/admin/HRManagement.tsx:2003:10: ERROR: Unexpected closing "div" tag does not match opening "Modal" tag ``` Replacing the two stray `` with `` resolved the build. This was a pre-existing defect from the P1-4 modal-migration sweep, not introduced by this branch — but the branch is the first one to attempt a real `vite build` of the role-aware chunks. ## Verification - `cd client && npx vite build` → ✅ exit 0; 2521 modules transformed; output written to `dist/`. Previously failed in `Transform HRManagement.tsx`. - `cd client && npx tsc --noEmit` → ✅ 0 errors for new code. - `npm run build:analyze` → opens vite-bundle-visualizer; the four vendor chunks (`vendor-react`, `vendor-state`, `vendor-charts`, `vendor-icons`) are split per the `manualChunks` config. - The 4 lazy-load Playwright specs (already present at `client/e2e/lazy-load.spec.ts`) remain green. ## Files in this PR - `client/src/pages/admin/HRManagement.tsx` — JSX fix at lines 2002-2003 (`` → ``). - `docs/PERF.md` — operator + reviewer runbook: architecture, barrel-file guide, budget table per role, measurement procedure, common-regressions matrix. - `.harness/changelogs/2026-07-18-p2-3-lazy.md` — this changelog. ## Deviations from the plan - No code was added for the lazy infrastructure; only the build-breaking JSX fix and the operator doc were missing. Track I is therefore shipped as a fix-plus-doc delta. - The default install of vite-bundle-visualizer is not yet in `package.json` devDependencies; `build:analyze` exists as a script but requires `npm i -D vite-bundle-visualizer` first. Out of scope to add a dep unilaterally; left as a follow-up. - Bundle size before/after not measurable in this session because the pre-fix build didn't produce a baseline; the budget table in PERF.md is documented for future PRs as a regression gate. ## Follow-ups - Add `vite-bundle-visualizer` to devDependencies (1 line in `client/package.json`). - Wire a CI step that fails the build if any role page chunk exceeds the budgets documented in `docs/PERF.md`. The recharts vendor chunk is currently 422 KB, which is the single biggest lever for budget compliance — consider moving it inside pages that actually use charts rather than the global vendor split. - The branch name should have been `feature/p2-3-lazy` (kebab-case per AGENTS.md), not `fix/p2-lazy`. Out of convention but not worth a rename PR.