diff --git a/.claude/skills/contributing-to-loopover/reference.md b/.claude/skills/contributing-to-loopover/reference.md index 3eae254642..63c5a32c4a 100644 --- a/.claude/skills/contributing-to-loopover/reference.md +++ b/.claude/skills/contributing-to-loopover/reference.md @@ -55,6 +55,20 @@ jobs run only if their path filter matched; on push to `main`, everything runs. | ui → typecheck | `tsc --noEmit` (UI) | `npm run ui:typecheck` | UI type error | | ui → tests | vitest jsdom (UI) | `npm run ui:test` | failing UI component test | | ui → build | UI build | `npm run ui:build` | build failure (note: it re-runs `ui:openapi` internally) | + +**Verifying the built artifact actually serves — do not use `apps/loopover-ui`'s `preview` in the raw +TanStack Start template sense.** `apps/loopover-ui` targets nitro's `cloudflare-module` preset +(`vite.config.ts`), which repackages the server build as `dist/server/index.mjs`. `@tanstack/start-plugin-core`'s +`vite preview` integration derives the file it imports from the vite-level server entry's basename +(`server.js`) and has no awareness of nitro's repackaging, so it 500s with `ERR_MODULE_NOT_FOUND` on +every request after any build — no upstream fix exists as of `@tanstack/start-plugin-core@1.171.24` +(confirmed identical to the installed `1.171.19`). `apps/loopover-ui/package.json`'s `preview` script is +already fixed to use `wrangler dev --config dist/server/wrangler.json --ip 127.0.0.1 --port 4173 --local` +instead (the same mechanism `deploy:built`/`version:built` use) — run `npm --workspace @loopover/ui run +build && npm --workspace @loopover/ui run preview`, or `npm run ui:preview` from the repo root (which +builds everything first), to actually exercise the production build locally. `test/unit/loopover-ui-preview-script.test.ts` +regression-guards the script itself against reverting to `vite preview`. + | ui → extension lint | `eslint` (VS Code + miner extensions) | `npm run extension:lint && npm run miner-extension:lint` | extension ESLint error (same `push \|\| ui==true` trigger as the `ui →` rows) | | ui → extension typecheck | `tsc --noEmit` (extensions) | `npm run extension:typecheck && npm run miner-extension:typecheck` | extension type error (same `push \|\| ui==true` trigger) | | security (PR only) | dependency-review (moderate+) | `npm audit --audit-level=moderate` | a **newly added** dep has a moderate+ advisory | diff --git a/apps/loopover-ui/package.json b/apps/loopover-ui/package.json index e1fa31d6bb..3dad8b8d37 100644 --- a/apps/loopover-ui/package.json +++ b/apps/loopover-ui/package.json @@ -14,7 +14,7 @@ "build:dev": "vite build --mode development", "bundle-analysis": "bundle-analyzer ./dist/client --bundle-name=loopover-ui --upload-token=$CODECOV_TOKEN", "deploy:built": "wrangler deploy --config dist/server/wrangler.json", - "preview": "vite preview", + "preview": "wrangler dev --config dist/server/wrangler.json --ip 127.0.0.1 --port 4173 --local", "version:built": "wrangler versions upload --config dist/server/wrangler.json", "typecheck": "tsc --noEmit", "lint": "eslint .", diff --git a/test/unit/loopover-ui-preview-script.test.ts b/test/unit/loopover-ui-preview-script.test.ts new file mode 100644 index 0000000000..184b566e50 --- /dev/null +++ b/test/unit/loopover-ui-preview-script.test.ts @@ -0,0 +1,21 @@ +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +describe("apps/loopover-ui preview script", () => { + // Regression guard: @tanstack/start-plugin-core's preview-server-plugin derives the file it imports + // from the vite-level server entry's basename ("server" -> server.js), but this app's nitro + // cloudflare-module preset (vite.config.ts) repackages the server build as dist/server/index.mjs -- + // server.js is never produced, so bare `vite preview` 500s on every request after any build, with no + // upstream fix available as of @tanstack/start-plugin-core@1.171.24 (latest at time of writing). wrangler + // dev against the real built Worker -- the same mechanism deploy:built/version:built already use just + // above this script -- is the only local command that actually serves this app's production build. + it("uses wrangler dev against the built Cloudflare Worker output, not the broken vite preview", () => { + const pkg = JSON.parse(readFileSync("apps/loopover-ui/package.json", "utf8")) as { + scripts?: Record; + }; + + expect(pkg.scripts?.preview).toBe( + "wrangler dev --config dist/server/wrangler.json --ip 127.0.0.1 --port 4173 --local", + ); + }); +});