Files
triggerdotdev--trigger.dev/apps/webapp/vite.config.ts
Matt Aitken 949e9cf1ec fix(webapp): show the real app version instead of v0.0.0 in organization settings (#4611)
## Summary

Since the move from the Remix compiler to Vite
([#4188](https://github.com/triggerdotdev/trigger.dev/pull/4188)), the
"App version" on the organization settings page shows `v0.0.0` unless
the image was built from a semver release tag (which bakes in
`BUILD_APP_VERSION`). Self-hosted builds and any image built from `main`
are affected. This restores the real version.

## Root cause

The Vite SSR bundle resolves workspace packages to TS source via the
`@triggerdotdev/source` condition, so `@trigger.dev/core`'s `VERSION`
constant is bundled as its raw `"0.0.0"` placeholder.
`scripts/updateVersion.ts` still stamps the real version at build time,
but only into the packages' dist output, which the bundle no longer
reads. The old Remix compiler bundled the stamped dist, which is why
this used to work.

The fix is a small Vite plugin that applies the same substitution to the
source version modules of `@trigger.dev/core` and `@trigger.dev/sdk`
during bundling. Beyond the settings page, this also restores real
values in the `trigger-version` request header and the version
attributes the bundled packages emit.

Verified by building the server bundle and confirming the VERSION
constants carry the package versions, with no `"0.0.0"` occurrences left
in the build output.
2026-08-14 10:45:58 +01:00

110 lines
3.5 KiB
TypeScript

import { readFileSync } from "node:fs";
import { vitePlugin as remix } from "@remix-run/dev";
import { defaultClientConditions, defaultServerConditions, defineConfig, type Plugin } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
const packageVersions: Record<string, string> = Object.fromEntries(
["core", "trigger-sdk"].map((pkg) => [
pkg,
(
JSON.parse(
readFileSync(new URL(`../../packages/${pkg}/package.json`, import.meta.url), "utf-8")
) as { version: string }
).version,
])
);
/**
* The `@triggerdotdev/source` condition resolves workspace packages to TS source, where
* each VERSION constant is the "0.0.0" placeholder (scripts/updateVersion.ts stamps the
* real version, but only in dist output, which this bundle never reads). Stamp the version
* modules during bundling so VERSION carries the real package version everywhere it's used.
*/
function stampPackageVersions(): Plugin {
return {
name: "stamp-package-versions",
transform(code, id) {
const match = id
.split("?")[0]
.match(/packages[/\\](core|trigger-sdk)[/\\]src[/\\]version\.ts$/);
if (match) {
return {
code: code.replace('"0.0.0"', JSON.stringify(packageVersions[match[1]])),
map: null,
};
}
},
};
}
export default defineConfig({
plugins: [
remix({
ignoredRouteFiles: ["**/.*"],
// .mjs so the CJS server.ts wrapper can dynamic-import it
serverBuildFile: "index.mjs",
}),
tsconfigPaths(),
stampPackageVersions(),
],
resolve: {
// Resolve workspace packages to TS source (same condition the CLI uses)
conditions: ["@triggerdotdev/source", ...defaultClientConditions],
// Browser polyfills for node builtins used by client deps (antlr4ts)
alias: [
{ find: /^assert$/, replacement: "assert/" },
{ find: /^util$/, replacement: "util/" },
],
},
optimizeDeps: {
// Crawl all routes up front - mid-session re-optimization duplicates React
entries: ["./app/entry.client.tsx", "./app/root.tsx", "./app/routes/**/*.{ts,tsx}"],
esbuildOptions: {
// node globals for prebundled CJS deps (client-only by construction)
define: { global: "globalThis" },
inject: ["./vite/node-globals-shim.js"],
},
},
server: {
cors: false,
watch: {
// Seeder scripts are not app code; running them must not full-reload the dashboard.
ignored: ["**/seed-*.mts"],
},
warmup: {
clientFiles: ["./app/entry.client.tsx", "./app/root.tsx", "./app/components/**/*.tsx"],
ssrFiles: ["./app/entry.server.tsx", "./app/root.tsx"],
},
},
build: {
sourcemap: true,
rollupOptions: {
// Prisma wrappers and pg have CJS/native pieces Rollup can't inline
external: [/^@trigger\.dev\/database$/, /^@internal\/run-ops-database$/, /^pg$/],
},
},
ssr: {
resolve: {
conditions: ["@triggerdotdev/source", ...defaultServerConditions],
externalConditions: ["@triggerdotdev/source", "node"],
},
// CJS Prisma clients and native pg must load through node
external: ["@trigger.dev/database", "@internal/run-ops-database", "pg"],
// CJS deps whose named exports node's ESM interop can't detect
noExternal: [
/^@radix-ui\//,
"react-use",
"cron-parser",
"@kapaai/react-sdk",
"@fingerprintjs/fingerprintjs-pro-react",
"@fingerprintjs/fingerprintjs-pro",
"@fingerprintjs/fingerprintjs-pro-spa",
"recharts",
/^victory-vendor/,
],
optimizeDeps: {
include: ["cron-parser"],
},
},
});