feat: task 1.3 vite dev proxy + tsconfig hardening
Same-origin dev proxy via Vite's server.proxy:
- /api/* -> ${VITE_DEV_DIRECTUS_URL}/* (Directus REST + GraphQL)
- /ws-business -> ws://.../websocket (Directus business-plane WS)
- /ws-live -> ${VITE_DEV_PROCESSOR_WS_URL} (Processor live WS, Phase 1.5)
WS proxy targets derive ws:// scheme from the http(s) Directus URL.
loadEnv reads VITE_DEV_* overrides; sensible localhost defaults.
tsconfig.app.json: noUncheckedIndexedAccess + noImplicitOverride.
.env.example documents the two override vars; .env.local is gitignored
via the existing *.local pattern.
README "Local dev" section: proxy table + override instructions + port
collision workaround.
Deviation: spec called for .env.dev.example/.env.dev.local but Vite's
dev mode is "development" not "dev", so mode-specific files would be
.env.development.* and Vite wouldn't auto-load .env.dev.local. Switched
to the standard Vite .env.example/.env.local convention. Documented in
the task's Done section.
Plus: backfill 1.2 commit SHA (9918418) in its Done section.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Local dev overrides for vite.config.ts proxy targets.
|
||||
# Copy to .env.local (gitignored, auto-loaded by Vite) and edit to point
|
||||
# at your local services. Both have sensible defaults matching the dev
|
||||
# compose stack — only override when you need to.
|
||||
|
||||
# Directus REST + GraphQL + business-plane WebSocket host.
|
||||
# Defaults to http://localhost:8055 (the dev compose default).
|
||||
# The WS proxy target is derived by swapping http(s):// for ws(s)://.
|
||||
VITE_DEV_DIRECTUS_URL=http://localhost:8055
|
||||
|
||||
# Processor live-position WebSocket. Defaults to ws://localhost:8081
|
||||
# (the LIVE_WS_PORT default in the processor's Phase 1.5 task spec).
|
||||
VITE_DEV_PROCESSOR_WS_URL=ws://localhost:8081
|
||||
@@ -50,8 +50,8 @@ These rules govern every task. Any deviation must be discussed and documented as
|
||||
| # | Task | Status | Landed in |
|
||||
| ---- | ------------------------------------------------------------------------------------------------------------ | ------ | --------- |
|
||||
| 1.1 | Project scaffold (Vite + React + TS) | 🟩 | (manual) |
|
||||
| 1.2 | [Stack rounding-out (Tailwind + shadcn/ui + deps + Prettier)](./phase-1-foundation/02-stack-rounding-out.md) | 🟩 | local (uncommitted) |
|
||||
| 1.3 | [Vite dev proxy + path aliases + tsconfig hardening](./phase-1-foundation/03-vite-dev-proxy.md) | ⬜ | — |
|
||||
| 1.2 | [Stack rounding-out (Tailwind + shadcn/ui + deps + Prettier)](./phase-1-foundation/02-stack-rounding-out.md) | 🟩 | `9918418` |
|
||||
| 1.3 | [Vite dev proxy + path aliases + tsconfig hardening](./phase-1-foundation/03-vite-dev-proxy.md) | 🟩 | `PENDING_SHA` |
|
||||
| 1.4 | [Runtime config endpoint](./phase-1-foundation/04-runtime-config.md) | ⬜ | — |
|
||||
| 1.5 | [Directus auth client (cookie mode + refresh)](./phase-1-foundation/05-directus-auth-client.md) | ⬜ | — |
|
||||
| 1.6 | [Login page](./phase-1-foundation/06-login-page.md) | ⬜ | — |
|
||||
|
||||
@@ -107,4 +107,4 @@ Stack rounded out: Tailwind 4 via `@tailwindcss/vite`, shadcn/ui (slate base / n
|
||||
|
||||
**Smoke check:** `pnpm typecheck`, `pnpm lint`, `pnpm format:check`, `pnpm build` all green. `App.tsx` renders a Tailwind-styled centered card with a shadcn `Button` to prove the toolchain works end-to-end. Bundle: 222KB raw / 70KB gzipped.
|
||||
|
||||
(Commit SHA pending — work landed locally, not yet committed.)
|
||||
Landed in `9918418`.
|
||||
|
||||
@@ -132,4 +132,18 @@ One gotcha: the proxy's `target` for a WS route must use a `ws://` or `wss://` s
|
||||
|
||||
## Done
|
||||
|
||||
(Filled in when the task lands.)
|
||||
`vite.config.ts` switched to the function form, reads env via `loadEnv(mode, process.cwd(), 'VITE_')`, exposes three proxy routes:
|
||||
|
||||
- `/api/*` → `${VITE_DEV_DIRECTUS_URL}/*` (default `http://localhost:8055`), strips the `/api` prefix.
|
||||
- `/ws-business` → derived `ws://...` from the Directus URL, rewrites to `/websocket`.
|
||||
- `/ws-live` → `${VITE_DEV_PROCESSOR_WS_URL}` (default `ws://localhost:8081`), strips the `/ws-live` prefix.
|
||||
|
||||
`tsconfig.app.json` gains `noUncheckedIndexedAccess: true` and `noImplicitOverride: true`. The `@/*` path alias was already set up in 1.2 (deviation noted there).
|
||||
|
||||
`.env.example` (committed) documents the two proxy override env vars; `.env.local` (already gitignored via the existing `*.local` pattern) is the developer's actual values file. README "Local dev" section rewritten with the proxy table and override instructions.
|
||||
|
||||
**Deviation from spec:** the spec called for `.env.dev.example` / `.env.dev.local` but Vite's mode for `pnpm dev` is `development` (not `dev`), so mode-specific files would be `.env.development.local` and Vite wouldn't auto-load `.env.dev.local` at all. Switched to the standard Vite convention `.env.example` (committed docs) + `.env.local` (auto-loaded in any mode, gitignored). Cleaner and matches Vite's actual behaviour.
|
||||
|
||||
**Smoke check:** `pnpm typecheck`, `pnpm lint`, `pnpm format:check`, `pnpm build` all green. Stricter tsconfig didn't surface any existing issues (current code is small).
|
||||
|
||||
Landed in `PENDING_SHA`.
|
||||
|
||||
@@ -25,7 +25,7 @@ Implementation planning lives in `.planning/` — see `.planning/ROADMAP.md`.
|
||||
## Common scripts
|
||||
|
||||
| Command | Purpose |
|
||||
| -------------------- | --------------------------------------------- |
|
||||
| ------------------- | ------------------------------------------- |
|
||||
| `pnpm dev` | Start the Vite dev server on `:5173`. |
|
||||
| `pnpm build` | Type-check + production build into `dist/`. |
|
||||
| `pnpm preview` | Serve the built `dist/` for smoke testing. |
|
||||
@@ -45,7 +45,17 @@ Components land in `src/ui/primitives/` per `components.json`'s alias config. Ed
|
||||
|
||||
## Local dev
|
||||
|
||||
The Vite dev proxy (Phase 1.3) routes `/api`, `/ws-business`, `/ws-live` to the appropriate local services so the SPA dev experience matches the stage/prod reverse-proxy topology under one origin. Until 1.3 lands, the SPA runs standalone.
|
||||
The Vite dev server (`pnpm dev` on `:5173`) proxies three path namespaces to local services so everything runs same-origin — the same topology stage/prod gets via Traefik, no CORS workarounds needed.
|
||||
|
||||
| Path | Forwards to | Notes |
|
||||
| -------------- | ------------------------------------ | ----------------------------------------------------------------------------- |
|
||||
| `/api/*` | `${VITE_DEV_DIRECTUS_URL}/*` | Directus REST + GraphQL. Default `http://localhost:8055`. |
|
||||
| `/ws-business` | `${VITE_DEV_DIRECTUS_URL}/websocket` | Directus business-plane WebSocket (auto-derived ws:// scheme). |
|
||||
| `/ws-live` | `${VITE_DEV_PROCESSOR_WS_URL}/` | Processor live-position WebSocket. Default `ws://localhost:8081` (Phase 1.5). |
|
||||
|
||||
Override per-developer by copying `.env.example` to `.env.local` and editing — Vite auto-loads `.env.local` in any mode and the values flow into `vite.config.ts` via `loadEnv`.
|
||||
|
||||
If the dev port `5173` collides with another Vite app, run with `VITE_PORT=5174 pnpm dev` (or pin a different port in `vite.config.ts`).
|
||||
|
||||
## CI
|
||||
|
||||
|
||||
+3
-1
@@ -24,7 +24,9 @@
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
+37
-2
@@ -1,14 +1,49 @@
|
||||
import path from 'node:path';
|
||||
import { defineConfig } from 'vite';
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), 'VITE_');
|
||||
const directusUrl = env.VITE_DEV_DIRECTUS_URL ?? 'http://localhost:8055';
|
||||
const processorWsUrl = env.VITE_DEV_PROCESSOR_WS_URL ?? 'ws://localhost:8081';
|
||||
// The WS proxy target needs the ws:// scheme; derive from the http(s) URL.
|
||||
const directusWsUrl = directusUrl.replace(/^http(s?):\/\//, 'ws$1://');
|
||||
|
||||
return {
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
// Directus REST + GraphQL. Strip /api prefix; SPA hits relative URLs.
|
||||
'/api': {
|
||||
target: directusUrl,
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => p.replace(/^\/api/, ''),
|
||||
},
|
||||
// Directus business-plane WebSocket. Strip /ws-business; rewrite to
|
||||
// Directus's actual /websocket path.
|
||||
'/ws-business': {
|
||||
target: directusWsUrl,
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => p.replace(/^\/ws-business/, '/websocket'),
|
||||
},
|
||||
// Processor live-position WebSocket. Strip /ws-live; Processor binds
|
||||
// bare (no path prefix) per the Phase 1.5 task spec.
|
||||
'/ws-live': {
|
||||
target: processorWsUrl,
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => p.replace(/^\/ws-live/, ''),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user