100 lines
3.8 KiB
TypeScript
100 lines
3.8 KiB
TypeScript
import { reactRouter } from "@react-router/dev/vite";
|
|
import { sentryVitePlugin } from "@sentry/vite-plugin";
|
|
import tailwindcss from "@tailwindcss/vite";
|
|
import { visualizer } from "rollup-plugin-visualizer";
|
|
import { defineConfig, type PluginOption } from "vite";
|
|
import { envOnlyMacros } from "vite-env-only";
|
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
|
|
import { resolveAssetBase } from "./app/utils/build/assetCdnBase";
|
|
import { shouldSuppressBuildWarning } from "./app/utils/build/buildWarningTriage";
|
|
import { getManualChunkName } from "./app/utils/build/manualChunks";
|
|
|
|
// Bundle visualizer (#71) — opt-in via ANALYZE_BUNDLE=true so the production
|
|
// build keeps its current footprint. Outputs an interactive treemap to
|
|
// apps/web/build/stats.html that includes both raw and gzip sizes per chunk.
|
|
// See docs/architecture/bundle-budgets.md for the inspection workflow.
|
|
const visualizerPlugin: PluginOption[] =
|
|
process.env.ANALYZE_BUNDLE === "true"
|
|
? [
|
|
visualizer({
|
|
filename: "build/stats.html",
|
|
template: "treemap",
|
|
gzipSize: true,
|
|
brotliSize: true,
|
|
open: false,
|
|
emitFile: false,
|
|
}) as PluginOption,
|
|
]
|
|
: [];
|
|
|
|
// Source-map generation is opt-in so bundle-budget and local production builds
|
|
// do not spend time writing artifacts that only the Sentry release path needs.
|
|
// CI quality builds set TOOLCTRL_BUILD_SOURCEMAPS=1 before uploading the
|
|
// client maps as an artifact for the reusable Sentry release job.
|
|
const buildSourcemapsEnabled = process.env.TOOLCTRL_BUILD_SOURCEMAPS === "1";
|
|
|
|
// Source-map upload is gated on both SENTRY_AUTH_TOKEN and source-map
|
|
// generation, so local builds without a token build successfully and tokened
|
|
// builds do not try to upload maps unless the release lane explicitly opted in.
|
|
// The plugin is added in the dedicated CI/production release path (see
|
|
// docs/improvement-plan/02-observability/sentry-wiring-web.md, Step 9).
|
|
const sentryPlugin: PluginOption[] = process.env.SENTRY_AUTH_TOKEN && buildSourcemapsEnabled
|
|
? [
|
|
sentryVitePlugin({
|
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
org: process.env.SENTRY_ORG,
|
|
project: process.env.SENTRY_PROJECT ?? "boilerplate-web",
|
|
release: process.env.SENTRY_RELEASE ? { name: process.env.SENTRY_RELEASE } : undefined,
|
|
sourcemaps: {
|
|
assets: "./build/**",
|
|
filesToDeleteAfterUpload: "./build/**/*.map",
|
|
},
|
|
// Telemetry off — we self-host and never want to phone home.
|
|
telemetry: false,
|
|
}),
|
|
]
|
|
: [];
|
|
|
|
export default defineConfig(({ mode }) => ({
|
|
// Asset CDN base — when ASSET_CDN_URL is set the production build emits
|
|
// asset URLs prefixed with the CDN origin (e.g. https://cdn.example.com/assets/app-3f4a1b.js).
|
|
// Local dev intentionally ignores the var so the Vite dev server keeps serving from `/`.
|
|
// See docs/improvement-plan/03-scaling-infrastructure/asset-cdn.md and docs/ops/asset-cdn.md.
|
|
base: resolveAssetBase(process.env, mode),
|
|
resolve: {
|
|
alias: {
|
|
"@toolctrl/queue/runtime": "/dev/null",
|
|
},
|
|
},
|
|
server: { port: 3000 },
|
|
plugins: [envOnlyMacros(), tailwindcss(), reactRouter(), tsconfigPaths(), ...sentryPlugin, ...visualizerPlugin],
|
|
ssr: {
|
|
noExternal: ["minimatch"],
|
|
},
|
|
optimizeDeps: {
|
|
esbuildOptions: {
|
|
target: "esnext",
|
|
},
|
|
},
|
|
build: {
|
|
target: "esnext",
|
|
chunkSizeWarningLimit: 1800,
|
|
// Opt-in for Sentry release lanes; bundle-budget and local production
|
|
// builds keep this off for faster builds and smaller temporary output.
|
|
sourcemap: buildSourcemapsEnabled,
|
|
rollupOptions: {
|
|
output: {
|
|
manualChunks: getManualChunkName,
|
|
},
|
|
onwarn(warning, defaultHandler) {
|
|
if (shouldSuppressBuildWarning(warning)) {
|
|
return;
|
|
}
|
|
|
|
defaultHandler(warning);
|
|
},
|
|
},
|
|
},
|
|
}));
|