History

Pin VITE_PUBLIC_ANALYTICS_PATH for cloud build

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.

Rhys Sullivan committed 6 months ago

Commit 242c2891 parent 40353be3 files · +32 −8Browse files

Unified · Split

3 files
  1. apps/cloud/package.json +1 −1
  2. apps/cloud/scripts/build.mjs +25 −0
  3. apps/cloud/vite.config.ts +6 −7
apps/cloud/package.json+1−1
@@ -14,7 +14,7 @@ · 13 unmodified lines
1414 "db:studio:prod": "op run --env-file=.env.production -- drizzle-kit studio",
1515 "db:migrate:prod": "op run --env-file=.env.production -- drizzle-kit migrate",
1616 "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",
1818 "preview": "vite preview",
1919 "deploy": "op run --env-file=.env.production -- bun run build && op run --env-file=.env.production -- wrangler deploy",
2020 "cf-typegen": "wrangler types",
apps/cloud/scripts/build.mjs+25−0
@@ -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+}
apps/cloud/vite.config.ts+6−7
@@ -1,4 +1,3 @@
1−import { randomUUID } from "node:crypto";
21 import { fileURLToPath } from "node:url";
32 import { defineConfig, loadEnv, type Plugin } from "vite";
43 import { cloudflare } from "@cloudflare/vite-plugin";
@@ -42,17 +41,17 @@ const loadWranglerPublicVars = () => { · 37 unmodified lines
4241 );
4342 };
4443
45−let generatedAnalyticsPath: string | undefined;
46−const getGeneratedAnalyticsPath = () => {
47− generatedAnalyticsPath ??= randomUUID().slice(0, 8);
48− return generatedAnalyticsPath;
49−};
44+// VITE_PUBLIC_ANALYTICS_PATH is generated once per build by `scripts/build.mjs`
45+// and inherited via process.env, so the client and SSR/Cloudflare environment
46+// builds bake the same value. The fallback "a" is for `vite dev`, where the
47+// proxy isn't routed anyway.
48+const ANALYTICS_PATH = process.env.VITE_PUBLIC_ANALYTICS_PATH ?? "a";
5049
5150 export default defineConfig(({ mode }) => {
5251 const env = loadEnv(mode, process.cwd(), "");
5352 const publicEnv = {
5453 ...loadWranglerPublicVars(),
55− VITE_PUBLIC_ANALYTICS_PATH: getGeneratedAnalyticsPath(),
54+ VITE_PUBLIC_ANALYTICS_PATH: ANALYTICS_PATH,
5655 ...env,
5756 };
5857