From 4256d93aefc991223ed3bd19bd9fe4cf904c1ef8 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:24:23 -0700 Subject: [PATCH] fix(ui): use wrangler dev instead of broken vite preview (#7621) apps/loopover-ui's preview script (vite preview) 500s on every request after any build: Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../dist/server/server.js'. Reproduced directly on main. vite.config.ts pins nitro's cloudflare-module preset, which repackages the server build as dist/server/index.mjs (confirmed via a real build). @tanstack/start-plugin-core's vite preview integration derives the file it imports from the vite-level server entry (tanstackStart.server.entry: "server" -> server.js), with no awareness of nitro's repackaging -- server.js is never produced. Confirmed identical logic between the installed @tanstack/start-plugin-core@1.171.19 and latest 1.171.24: no upstream fix exists yet for a nitro-repackaged deploy target. Use wrangler dev against the real built Worker instead -- the same mechanism deploy:built/version:built already use just above this script, and what the root's existing ui:preview already does for the full monorepo build. apps/loopover-miner-ui's own vite preview is unaffected (plain Node preset, no nitro repackaging) and left untouched. Verified end-to-end: built the real app, ran the fixed preview script, confirmed a genuine 200 with real SSR-rendered HTML via a direct HTTP request. Added a regression test asserting the script's exact value, and documented the root cause + correct verification command in the contributing skill docs. Closes #7621 --- .../contributing-to-loopover/reference.md | 14 +++++++++++++ apps/loopover-ui/package.json | 2 +- test/unit/loopover-ui-preview-script.test.ts | 21 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/unit/loopover-ui-preview-script.test.ts 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", + ); + }); +});