import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { cloudflare } from "@cloudflare/vite-plugin"; import { defineConfig } from "vite"; import viteReact from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; /** * wrangler.jsonc is the production config. Local runs (`vite dev`, and `bun run preview`, which builds with * GITFOR_LOCAL=1) layer the dev overrides below on it; `bun run deploy` builds without them. Local runs must * never bind a deployed Artifacts namespace: an orphan sweep or a wiped local D1 would treat the other side's * repositories as orphans, so every namespace and trigger filter becomes `-dev`. */ const DEV_NAMESPACE_SUFFIX = "-dev"; // USERCONTENT_ORIGIN is cleared so dev serves user content from `usercontent.localhost:` (see // usercontent-origin.ts) instead of redirecting raw files, avatars and archives to the production origin. const DEV_VARS = { PUBLIC_URL: "http://localhost:3000", GITFOR_LOCAL: "true", USERCONTENT_ORIGIN: "" }; function devName(namespace: string): string { return namespace.endsWith(DEV_NAMESPACE_SUFFIX) ? namespace : `${namespace}${DEV_NAMESPACE_SUFFIX}`; } /** `src/fns/repos.ts` + `exploreRepos` -> `fns.repos.exploreRepos`; the source is public, so nothing leaks. */ function serverFnId({ filename, functionName }: { filename: string; functionName: string }): string { const file = filename .replace(/^(?:.*\/)?src\//, "") .replace(/\.[cm]?tsx?$/, "") .replace(/[^A-Za-z0-9]+/g, "."); return `${file}.${functionName.replace(/_createServerFn_handler$/, "")}`; } export default defineConfig(({ command, isPreview }) => { const local = (command === "serve" && !isPreview) || process.env.GITFOR_LOCAL === "1"; return { server: { port: 3000, // The Worker answers CORS itself (e.g. the editor API's preflights from its opaque-origin frame). cors: false, }, resolve: { tsconfigPaths: true, }, plugins: [ cloudflare({ viteEnvironment: { name: "ssr" }, ...(local ? { // Mutate in place: a returned partial is deep-merged and its arrays are appended, which would // leave the production namespace binding and triggers alongside the dev ones. config: (config) => { for (const binding of config.artifacts ?? []) binding.namespace = devName(binding.namespace); for (const event of config.triggers?.events ?? []) { if (event.filter?.namespace) event.filter.namespace = devName(event.filter.namespace); } config.vars = { ...config.vars, ...DEV_VARS, ARTIFACTS_NAMESPACE: devName(String(config.vars?.ARTIFACTS_NAMESPACE ?? "stig")), }; }, } : {}), }), tailwindcss(), tanstackStart({ srcDirectory: "src", // Readable ids (fns.repos.exploreRepos) so request metrics name the server function, not a hash. serverFns: { generateFunctionId: serverFnId }, }), viteReact(), ], }; });