Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
4.0 KiB
Migrate steam-backlog-enforcer/web to Astro (no React)
what
Rebuild the loopback dashboard (web/) as Astro 7 static pages, one per
section. Scripts fetch and render in vanilla TS, and stateful widgets become
custom elements. TanStack Router and React Query go away.
steam_backlog_enforcer._web_server keeps serving web/dist on
127.0.0.1:8000, with its per-launch token.
steps
- Do
~/src/utils/web_ui/TODO-astro-port.mdfirst. Then add@kuhyx/web-uiat the new tag, fortokens.cssonly. - Pages. The router routes become
src/pages/:index(dashboard),backlog,picks,library,store,gaming,jobs,system,setup, and404.astro./jobs/$jobIdbecomesjobs/?id=<id>, because static output cannot prerender unknown ids.shell/AppShell.tsxbecomeslayouts/Shell.astro, with nav, health and the job indicator.
- Server (
_web_server.py):- Serve
<path>/index.htmlbefore the SPA fallback. - Inject the token into EVERY served
.html, not only the rootindex.html, and mark each one no-cache. - Add tests to
tests/test_web_server_static.py.
- Serve
_web_build.pycallsnpm run build. Change it topnpm build, and update its "npm missing" message. Deleteweb/package-lock.json, so pnpm is the only lockfile.- Rewrite the 45 React files:
screens/*(10, plussystem/*3) become.astropages and sections.components/*(10):GameTableandFilterPanelbecome a<game-table>custom element. The budget cards are.astroplus a poller.TimelineChartandBudgetHistoryChartbecome SVG builders insrc/lib/charts/.commands/*(7):<command-palette>and<runner-dialog>custom elements on<dialog>.RunnerProviderbecomes a module-level store.jobs/*(4):<job-progress>subscribes to the SSEEventSource.library/*(3) becomes<game-browser>.ui/*(3) andshell/*(3) become.astro. Deleterouter.tsxandApp.tsx.- Hooks (
useBudgetPoll.ts,api/queries.tsand the other React-only.tsfiles) become plain fetch, poll and cache helpers insrc/lib/.
- Mock mode.
web/mock/plugin.tsstays a Vite plugin, added throughvite.pluginsinastro.config.mjswhenMODE=mock.dev:mockbecomesastro dev --mode mock. - Dependencies, from
web/, exact pins via pnpm:- Add
astro@7.4.4,@astrojs/check@0.9.12,eslint-plugin-astro@3.2.1and@testing-library/dom. - Remove
react,react-dom,@tanstack/react-query,@tanstack/react-router,@vitejs/plugin-react,babel-plugin-react-compiler,@babel/core,@rolldown/plugin-babeland@testing-library/react. - Drop direct
vite. Replace or delete the Vite templateweb/README.md.
- Add
- Tests. Use vitest 5.0.5 with
getViteConfig():- Elements and helpers are tested in jsdom against the
mock/world. - The Container API renders each page.
- Coverage is scoped to
src/**/*.ts.
- Elements and helpers are tested in jsdom against the
- There is no
[agent_ready]table. It is a loopback app, so skip AgentReady.
done
Run from web/:
pnpm install --frozen-lockfile && pnpm exec astro check && pnpm coverage && pnpm build
Then:
! grep -q '"react"' package.json && ! grep -qE '"(react-dom|@vitejs/plugin-react|@tanstack/react-[a-z]+)"' package.json && ! find src -name '*.tsx' | grep -q . && test ! -f package-lock.json
Both exit 0. Also run the repo root's
python -m pytest -q steam_backlog_enforcer/tests/test_web_server_static.py.
verify
Start the live server the way the repo does (_serve_startup.py) on
127.0.0.1:8000. Use a headless chromium on /, /library/ and
/jobs/?id=<real id>:
- Every page carries the token and the API calls return 200.
- The command palette runs a dry command.
- There are no console errors.
read first
~/src/utils/web_ui/TODO-astro-port.md(do it first)web/src/router.tsx,web/src/api/queries.ts,web/mock/plugin.ts,web/vite.config.tssteam_backlog_enforcer/_web_server.py,_web_auth.py,_web_build.py
REMOVE ME AFTER FINISH