Vite reloads vite.config.ts separately for the client and SSR/Cloudflare environments, so the previous module-scope memoization of randomUUID() ran twice and produced different ids. Client and server bundles baked mismatching paths, so the worker proxy never matched the SDK's requests and PostHog calls 404'd in production. Generate the path once in scripts/build.mjs before vite starts and inherit via process.env so every environment build sees the same value.
Unified · Split
| @@ -14,7 +14,7 @@ · 13 unmodified lines | |||
| 14 | "db:studio:prod": "op run --env-file=.env.production -- drizzle-kit studio", | 14 | "db:studio:prod": "op run --env-file=.env.production -- drizzle-kit studio", |
| 15 | "db:migrate:prod": "op run --env-file=.env.production -- drizzle-kit migrate", | 15 | "db:migrate:prod": "op run --env-file=.env.production -- drizzle-kit migrate", |
| 16 | "db:migrate:dev": "op run --env-file=.env.op -- drizzle-kit migrate", | 16 | "db:migrate:dev": "op run --env-file=.env.op -- drizzle-kit migrate", |
| 17 | "build": "turbo run build --filter @executor-js/vite-plugin && vite build", | 17 | "build": "node scripts/build.mjs", |
| 18 | "preview": "vite preview", | 18 | "preview": "vite preview", |
| 19 | "deploy": "op run --env-file=.env.production -- bun run build && op run --env-file=.env.production -- wrangler deploy", | 19 | "deploy": "op run --env-file=.env.production -- bun run build && op run --env-file=.env.production -- wrangler deploy", |
| 20 | "cf-typegen": "wrangler types", | 20 | "cf-typegen": "wrangler types", |
| @@ -0,0 +1,25 @@ | |||
| 1 | // Build wrapper that pins VITE_PUBLIC_ANALYTICS_PATH for the whole build. | ||
| 2 | // | ||
| 3 | // Vite reloads vite.config.ts separately for the client and SSR/Cloudflare | ||
| 4 | // environments, so a module-scoped randomUUID() ends up running twice and | ||
| 5 | // the two bundles bake different values. The browser SDK then targets a | ||
| 6 | // path the worker middleware never matches, and PostHog requests 404. By | ||
| 7 | // generating once here and putting it in process.env before vite starts, | ||
| 8 | // every environment build sees the same value. | ||
| 9 | |||
| 10 | import { spawnSync } from "node:child_process"; | ||
| 11 | import { randomBytes } from "node:crypto"; | ||
| 12 | |||
| 13 | if (!process.env.VITE_PUBLIC_ANALYTICS_PATH) { | ||
| 14 | process.env.VITE_PUBLIC_ANALYTICS_PATH = randomBytes(4).toString("hex"); | ||
| 15 | } | ||
| 16 | console.log(`[build] VITE_PUBLIC_ANALYTICS_PATH=${process.env.VITE_PUBLIC_ANALYTICS_PATH}`); | ||
| 17 | |||
| 18 | const steps = ["turbo run build --filter @executor-js/vite-plugin", "vite build"]; | ||
| 19 | |||
| 20 | for (const step of steps) { | ||
| 21 | const result = spawnSync(step, { stdio: "inherit", shell: true }); | ||
| 22 | if (result.status !== 0) { | ||
| 23 | process.exit(result.status ?? 1); | ||
| 24 | } | ||
| 25 | } | ||
| @@ -1,4 +1,3 @@ | |||
| 1 | import { randomUUID } from "node:crypto"; | ||
| 2 | import { fileURLToPath } from "node:url"; | 1 | import { fileURLToPath } from "node:url"; |
| 3 | import { defineConfig, loadEnv, type Plugin } from "vite"; | 2 | import { defineConfig, loadEnv, type Plugin } from "vite"; |
| 4 | import { cloudflare } from "@cloudflare/vite-plugin"; | 3 | import { cloudflare } from "@cloudflare/vite-plugin"; |
| @@ -42,17 +41,17 @@ const loadWranglerPublicVars = () => { · 37 unmodified lines | |||
| 42 | ); | 41 | ); |
| 43 | }; | 42 | }; |
| 44 | 43 | ||
| 45 | let generatedAnalyticsPath: string | undefined; | 44 | // VITE_PUBLIC_ANALYTICS_PATH is generated once per build by `scripts/build.mjs` |
| 46 | const getGeneratedAnalyticsPath = () => { | 45 | // and inherited via process.env, so the client and SSR/Cloudflare environment |
| 47 | generatedAnalyticsPath ??= randomUUID().slice(0, 8); | 46 | // builds bake the same value. The fallback "a" is for `vite dev`, where the |
| 48 | return generatedAnalyticsPath; | 47 | // proxy isn't routed anyway. |
| 49 | }; | 48 | const ANALYTICS_PATH = process.env.VITE_PUBLIC_ANALYTICS_PATH ?? "a"; |
| 50 | 49 | ||
| 51 | export default defineConfig(({ mode }) => { | 50 | export default defineConfig(({ mode }) => { |
| 52 | const env = loadEnv(mode, process.cwd(), ""); | 51 | const env = loadEnv(mode, process.cwd(), ""); |
| 53 | const publicEnv = { | 52 | const publicEnv = { |
| 54 | ...loadWranglerPublicVars(), | 53 | ...loadWranglerPublicVars(), |
| 55 | VITE_PUBLIC_ANALYTICS_PATH: getGeneratedAnalyticsPath(), | 54 | VITE_PUBLIC_ANALYTICS_PATH: ANALYTICS_PATH, |
| 56 | ...env, | 55 | ...env, |
| 57 | }; | 56 | }; |
| 58 | 57 | ||