From bf0e84d55af032bc22f065e25c5256dd4fc1375d Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Mon, 20 Jul 2026 16:52:51 +0800 Subject: [PATCH] fix(studio): make dev:studio-local work with the tanstack dev server (#48090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With `STUDIO_FRAMEWORK=tanstack`, `pnpm dev:studio-local` ran Studio in platform mode against the management API instead of the local CLI stack (`/` redirected to `/org` instead of `/project/default`). Vite selects env files by *mode* while the Next dev server selects them via `NODE_ENV=test`, so the tanstack dev server never loaded `.env.test` and the developer's `.env.local` (`NEXT_PUBLIC_IS_PLATFORM="true"`) won. The shell `NODE_ENV=test` also gets inlined into the dev client bundle by Vite, flipping `API_URL` to the vitest-only MSW host. `vite dev --mode test` isn't a viable fix: TanStack Start's dev-server plugin treats mode `test` as "running under vitest" and skips installing its SSR middleware, so every route 404s. Instead, dev keeps mode `development` and overlays the env cascade named by `MODE` on top. **Changed:** - `dev:studio-local` now also sets `MODE=test` (the same knob `build:tanstack` / `e2e:setup:selfhosted` already use) - `vite.config.ts` dev server: loads the `MODE`-named env cascade for the `NEXT_PUBLIC_*` client defines and seeds it into `process.env` for SSR, without clobbering shell-provided values (matching `serve.js` semantics, and safe against TanStack's own load-env plugin since `loadEnv` gives existing `process.env` priority) - `vite.config.ts` dev server: remaps a shell `NODE_ENV=test` to `development` so it can't be baked into the client bundle (mirrors `next dev` behavior) Platform-mode `pnpm dev:studio` sets no `MODE`, so the overlay is a no-op there. Build (`--mode test`), `serve.js`, and vitest (separate `vitest.config`) paths are unchanged. ## To test - `supabase` CLI installed, then: `STUDIO_FRAMEWORK=tanstack pnpm dev:studio-local` - Visit http://localhost:8082 — it should redirect to `/project/default` (not `/org`) and the Default Project page should load with data from the local stack (network requests go to `localhost:8082/api/platform/...`, no `api.supabase.(com|green)` calls) - `pnpm dev:studio` (platform mode, tanstack) still behaves as before — redirects to `/org` - Next path regression check: plain `pnpm dev:studio-local` (no `STUDIO_FRAMEWORK`) still works ## Summary by CodeRabbit * **Bug Fixes** * Improved local Studio development and test-mode environment handling. * Prevented test settings from being incorrectly embedded in the client application. * Ensured environment values are loaded consistently across development and test scenarios. * **Chores** * Updated the local Studio development command to explicitly use test mode. Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> --- apps/studio/vite.config.ts | 35 ++++++++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/apps/studio/vite.config.ts b/apps/studio/vite.config.ts index 1d4d09879f6..7300e86046c 100644 --- a/apps/studio/vite.config.ts +++ b/apps/studio/vite.config.ts @@ -538,11 +538,44 @@ export default defineConfig(({ command, mode }) => { if (command === 'build') { // Next's types declare NODE_ENV as read-only, so cast to assign it. ;(process.env as Record).NODE_ENV = 'production' + } else if (process.env.NODE_ENV === 'test') { + // `pnpm dev:studio-local` runs with a shell NODE_ENV=test (the Next + // path needs it to load `.env.test`), and Vite's + // define plugin inlines `process.env.NODE_ENV || mode` into the client — + // which would bake 'test' in and trip the vitest-only API_URL path. + // `next dev` always runs the bundle at 'development' regardless of the + // shell NODE_ENV; mirror that. Env-file selection is unaffected — the + // vite dev path selects `.env.test` via MODE=test (see envMode below), + // not NODE_ENV. + ;(process.env as Record).NODE_ENV = 'development' } + // `pnpm dev:studio-local` needs the `.env.test` cascade (self-hosted mode + // plus the supabase-cli keys that generateLocalEnv.js writes) — the Next + // path selects it via NODE_ENV=test, and the tanstack build via + // `--mode test` (e2e:setup:selfhosted). But `vite dev --mode test` is not + // an option: TanStack Start's dev-server plugin treats mode 'test' as + // "running under vitest" and skips installing its SSR middleware entirely, + // so every route 404s (see the `isTest` guard in devServerPlugin, + // @tanstack/start-plugin-core). So dev keeps mode 'development' and + // emulates the env cascade of the mode named by MODE instead: load it for + // the NEXT_PUBLIC_* defines below, and seed process.env for the SSR + // runtime. The seeding must not clobber shell-provided values (matching + // serve.js), and survives TanStack's own load-env plugin: that plugin + // Object.assigns loadEnv(mode) at configResolved — after this runs — and + // loadEnv gives existing process.env values priority over env-file values. + const envMode = command === 'serve' && process.env.MODE ? process.env.MODE : mode + // Inline NEXT_PUBLIC_* env vars at build time so `process.env.NEXT_PUBLIC_*` // works in the browser bundle (mirrors Next.js behaviour). - const env = loadEnv(mode, rootDir, '') + const env = loadEnv(envMode, rootDir, '') + + if (envMode !== mode) { + const processEnv = process.env as Record + for (const [key, value] of Object.entries(env)) { + processEnv[key] ??= value + } + } const publicEnvDefines = Object.fromEntries( Object.entries(env) .filter(([key]) => key.startsWith('NEXT_PUBLIC_')) diff --git a/package.json b/package.json index 4b5c8e45eae..6993678bcd0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "clean": "turbo run clean --parallel && rimraf -G node_modules/{*,.bin,.modules.yaml} .turbo/cache", "dev": "turbo run dev --parallel", "dev:studio": "turbo run dev --filter=studio --parallel", - "dev:studio-local": "pnpm setup:cli && NODE_ENV=test pnpm --prefix ./apps/studio dev", + "dev:studio-local": "pnpm setup:cli && NODE_ENV=test MODE=test pnpm --prefix ./apps/studio dev", "dev:docs": "turbo run dev --filter=docs --parallel", "dev:www": "turbo run dev --filter=www --parallel", "dev:design-system": "turbo run dev --filter=design-system --parallel",