deer-flow/docs/superpowers/plans/2026-07-31-frontend-performance-baseline-delivery.md
DanielWalnut 459dd78707
perf(frontend): bound delivery, bundles, and long-running UI work (#4622)
* docs: design frontend performance remediation

* docs: plan frontend performance remediation

* test(frontend): add route asset performance budgets

* perf(nginx): compress textual responses safely

* perf(frontend): lazy load case study media

* perf(frontend): bound static demo file tracing

* perf(frontend): restore static locale boundaries

* perf(frontend): defer closed workspace panels

* perf(frontend): split editors and deduplicate highlighting

* perf(frontend): index incremental message derivation

* perf(frontend): stabilize paged history cache policy

* perf(frontend): bound streaming markdown renders

* perf(frontend): virtualize message history

* perf(frontend): bound and virtualize chat lists

* perf(frontend): suspend inactive decorative animation

* perf(browser): stream latest frames as binary

* perf(artifacts): stream bounded text previews

* docs: finalize performance runtime boundaries

* style(backend): apply test formatting

* fix(frontend): keep translation functions client-side

* perf(frontend): defer decorative animation bundles

* test(frontend): lock optimized route budgets

* fix: harden frontend performance boundaries

* test(frontend): update i18n provider fixture

* fix(frontend): preserve sidebar pagination position

* style(backend): format artifact range test
2026-08-01 22:19:59 +08:00

85 lines
6.9 KiB
Markdown

# Frontend Performance Baseline and Delivery Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Turn the current route-weight and delivery findings into repeatable gates, enable safe compression, eliminate eager case-study image downloads, and remove the mock route's whole-project trace.
**Architecture:** A production-server measurement script owns route asset accounting and compares it with a checked-in budget. Nginx owns textual response compression. Landing images become semantic lazy images. Static demo data is exposed through an explicit manifest so route handlers never derive filesystem paths from request input.
**Tech Stack:** Next.js 16, TypeScript, Rstest, Node.js, Nginx, pnpm.
**Global Constraints:** Work only in `/Users/minimax/workspace/deer-flow/.worktrees/fix-frontend-performance`. Preserve current API routes. Do not gzip SSE or already-compressed media. Every fix follows RED, GREEN, regression proof, then commit.
## Task 1: Add a reproducible route-asset budget gate
**Files:**
- Create: `frontend/scripts/measure-route-assets.mjs`
- Create: `frontend/performance-budgets.json`
- Create: `frontend/tests/unit/scripts/measure-route-assets.test.ts`
- Modify: `frontend/package.json`
- Modify: `frontend/AGENTS.md`
- [ ] Write a failing unit test for exported `extractAssetPaths(html)` and `evaluateBudgets(measurements, budgets)`. Assert duplicate scripts are counted once and a one-byte overage fails with the route, asset class, actual bytes, and limit.
- [ ] Run `cd frontend && pnpm test -- tests/unit/scripts/measure-route-assets.test.ts` and record the missing-module failure.
- [ ] Implement pure helpers in `measure-route-assets.mjs`. The CLI must build with `NEXT_PUBLIC_STATIC_WEBSITE_ONLY=true`, spawn `next start` on a free local port, fetch `/`, `/workspace/chats`, the canonical demo thread, `/en/docs`, and `/blog/posts`, resolve referenced `/_next/static/` files under `.next/static`, and emit `performance-results.json`.
- [ ] Check in these initial ceilings, all below the measured baseline: `/` JS 1,050,000 and CSS 150,000; `/workspace/chats` JS 2,750,000 and CSS 150,000; demo chat JS 3,500,000 and CSS 150,000; `/en/docs` and `/blog/posts` JS 3,000,000 and CSS 230,000.
- [ ] Add `"perf:check": "node scripts/measure-route-assets.mjs --check"` and document the gate and static-demo requirement in `frontend/AGENTS.md`.
- [ ] Run the focused test GREEN. Temporarily lower the `/` JS budget to `1`, prove `pnpm perf:check` fails, restore the file, and defer the final passing gate until the bundle plan lands.
- [ ] Commit: `test(frontend): add route asset performance budgets`.
## Task 2: Enable safe Nginx compression
**Files:**
- Modify: `docker/nginx/nginx.conf`
- Modify: `docker/nginx/nginx.local.conf`
- Create: `backend/tests/test_nginx_compression.py`
- Modify: `AGENTS.md`
- [ ] Write a failing test that parses both configs and asserts the same compression policy: `gzip on`, `gzip_vary on`, minimum length 1024, compression level 5, and types limited to HTML default plus CSS, JavaScript, JSON, XML, and SVG. Assert `text/event-stream`, fonts, images other than SVG, audio, and video are absent.
- [ ] Run `cd backend && uv run pytest tests/test_nginx_compression.py -q` and capture RED.
- [ ] Add the identical directives to both `http` blocks. Include `gzip_proxied any`; do not add a wildcard content type.
- [ ] Update the service-topology note in root `AGENTS.md` to state that Nginx compresses textual responses but deliberately excludes SSE and pre-compressed media.
- [ ] Run the focused test GREEN. If local Nginx is available, start the configured service and verify `curl --compressed -I` returns `Content-Encoding: gzip` for HTML while an SSE response is uncompressed.
- [ ] Revert the directive block, prove the test fails, restore it, rerun GREEN.
- [ ] Commit: `perf(nginx): compress textual responses safely`.
## Task 3: Lazy-load landing case-study images
**Files:**
- Modify: `frontend/src/components/landing/sections/case-study-section.tsx`
- Create: `frontend/tests/unit/components/landing/case-study-section.dom.test.tsx`
- [ ] Write a DOM test that renders the section and asserts each card has an actual `img` with `loading="lazy"`, `decoding="async"`, intrinsic dimensions, descriptive alt text, and no inline/background-image URL.
- [ ] Run the focused test and capture RED against the CSS backgrounds.
- [ ] Replace background-image cards with a positioned `next/image` or native image. Keep the overlay and visual crop, set explicit `sizes`, and make only an above-the-fold image eager if measurement proves it is visible on initial viewport.
- [ ] Run the DOM test GREEN and verify in a browser/network trace that offscreen JPEG requests do not start before scrolling.
- [ ] Revert the component change, prove RED, restore, rerun GREEN.
- [ ] Commit: `perf(frontend): lazy load case study media`.
## Task 4: Replace request-derived mock filesystem traversal with a static manifest
**Files:**
- Modify: `frontend/src/core/threads/static-demo.ts`
- Modify: `frontend/src/app/mock/api/threads/[thread_id]/artifacts/[[...artifact_path]]/route.ts`
- Modify: `frontend/src/app/mock/api/threads/[thread_id]/history/route.ts`
- Modify: `frontend/src/app/mock/api/threads/search/route.ts`
- Modify: `frontend/src/app/workspace/page.tsx`
- Create: `frontend/tests/unit/core/threads/static-demo.test.ts`
- Create: `frontend/tests/unit/app/mock/static-artifact-route.test.ts`
- [ ] Add failing tests for `resolveStaticDemoArtifact(threadId, segments)` covering a known artifact, unknown thread, traversal segments, and encoded traversal. Add a route test that asserts the response comes from the manifest-backed resolver.
- [ ] Run both focused tests and capture RED.
- [ ] Define an explicit immutable demo manifest in `static-demo.ts`; normalize and validate all path segments before a lookup. Route handlers may read only paths returned by that manifest.
- [ ] Replace request-time `readdirSync`, `readFileSync`, and `statSync` in mock routes/workspace discovery with manifest imports or `fs/promises` during server execution. Keep response payloads byte-for-byte compatible.
- [ ] Run focused tests GREEN.
- [ ] Run `NEXT_PUBLIC_STATIC_WEBSITE_ONLY=true pnpm build` and assert the prior Turbopack "whole project unintentionally traced" warning and mock artifact import trace are absent.
- [ ] Revert the resolver use, prove the route test RED, restore, rerun focused tests and build.
- [ ] Commit: `perf(frontend): bound static demo file tracing`.
## Final verification
- [ ] Run `cd frontend && pnpm check && pnpm test`.
- [ ] Run `cd backend && uv run pytest tests/test_nginx_compression.py -q`.
- [ ] Run the static-demo production build and confirm zero unexpected-file/whole-project trace warnings.
- [ ] Record the new route measurements in the PR description; do not loosen a budget to make the gate pass.