import { readFileSync } from "node:fs"; import path from "node:path"; import { defineConfig } from "vitest/config"; import react from "@vitejs/plugin-react"; // @ts-expect-error Shared Node HTTP middleware also serves production bundles. import { createBundledContentHandler } from "./server/bundled-content.mjs"; // @ts-expect-error Local-only Node middleware is activated only in balance-lab-gui mode. import { createLocalBalanceLabApi } from "./server/local-balance-lab-api.mjs"; const packageVersion = (JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")) as { version: string }).version; export default defineConfig(({ mode }) => { const androidBuild = mode === "android"; const shelvedModesEnabled = mode === "shelved"; const balanceLabRuntime = mode === "balance-lab"; const localBalanceLabGui = mode === "balance-lab-gui"; const downloadableBuild = androidBuild || mode === "production" || shelvedModesEnabled; return { plugins: [react(), { name: "local-balance-lab-api", configureServer(server) { if (!localBalanceLabGui) return; const api = createLocalBalanceLabApi(); server.httpServer?.once("close", () => api.close()); server.middlewares.use((request, response, next) => { void api.handle(request, response).then((handled: boolean) => { if (!handled) next(); }).catch(next); }); }, }, { name: "bundled-content-preview", configurePreviewServer(server) { const serve = createBundledContentHandler(path.resolve(androidBuild ? "dist-android" : "dist")); server.middlewares.use((request, response, next) => { if (!serve(request, response, new URL(request.url ?? "/", "http://localhost").pathname)) next(); }); }, }, { name: "bundle-module-report", generateBundle(_options, bundle) { const chunks = Object.values(bundle) .filter((entry): entry is Extract => entry.type === "chunk") .map((chunk) => ({ file: chunk.fileName, entry: chunk.isEntry, dynamicEntry: chunk.isDynamicEntry, modules: Object.keys(chunk.modules).map((moduleId) => ( path.relative(process.cwd(), moduleId).split(path.sep).join("/") )).sort(), })); this.emitFile({ type: "asset", fileName: "bundle-module-report.json", source: `${JSON.stringify({ shelvedModesEnabled, chunks }, null, 2)}\n`, }); }, }], publicDir: balanceLabRuntime ? false : androidBuild ? ".android-public" : downloadableBuild ? ".web-public" : "public", define: { "import.meta.env.VITE_APP_VERSION": JSON.stringify(packageVersion), "import.meta.env.VITE_CONTENT_MODE": JSON.stringify(downloadableBuild ? "downloadable" : "bundled"), "import.meta.env.VITE_SHELVED_MODES_ENABLED": JSON.stringify(shelvedModesEnabled ? "true" : "false"), "import.meta.env.VITE_LOCAL_BALANCE_LAB_GUI": JSON.stringify(localBalanceLabGui ? "true" : "false"), }, resolve: { alias: { "@dungeonAssetModules": path.resolve( androidBuild || mode === "production" ? "src/game/dungeonAssetModules.android.ts" : "src/game/dungeonAssetModules.ts", ), "@shelvedGameRuntime": path.resolve( shelvedModesEnabled ? "src/app/ShelvedGameRuntime.enabled.tsx" : "src/app/ShelvedGameRuntime.disabled.tsx", ), "@shelvedGameScene": path.resolve( shelvedModesEnabled ? "src/scene/ShelvedGameScene.enabled.tsx" : "src/scene/ShelvedGameScene.disabled.tsx", ), "@shelvedModeRoutes": path.resolve( shelvedModesEnabled ? "src/app/ShelvedModeRoutes.tsx" : "src/app/ShelvedModeRoutes.disabled.tsx", ), "@shelvedOnlineGroupRuntime": path.resolve( shelvedModesEnabled ? "src/app/ShelvedOnlineGroupRuntime.enabled.ts" : "src/app/ShelvedOnlineGroupRuntime.disabled.ts", ), "@shelvedDungeonSession": path.resolve( shelvedModesEnabled ? "src/game/ShelvedDungeonSession.enabled.ts" : "src/game/ShelvedDungeonSession.disabled.ts", ), "@shelvedCompanionPanel": path.resolve( shelvedModesEnabled ? "src/ui/ShelvedCompanionPanel.enabled.tsx" : "src/ui/ShelvedCompanionPanel.disabled.tsx", ), "@shelvedHud": path.resolve( shelvedModesEnabled ? "src/ui/ShelvedHud.enabled.tsx" : "src/ui/ShelvedHud.disabled.tsx", ), }, }, server: { proxy: { "/api": "http://127.0.0.1:4173", "/content": "http://127.0.0.1:4173", }, watch: { // Asset-pipeline staging files are large, short-lived, and can be locked // while iCloud or conversion tools are writing them. They are not app // source, so watching them only risks taking the dev server down with // EBUSY on Windows. ignored: balanceLabRuntime ? ["**/*"] : [ "**/dungeon-pipeline/**", "**/playtest-artifacts/**", ...(localBalanceLabGui ? ["**/artifacts/balance-lab-gui-runtime/**"] : []), ], }, }, build: { target: "es2022", sourcemap: false, emptyOutDir: true, outDir: androidBuild ? "dist-android" : "dist", }, test: { environment: "node", include: ["src/**/*.test.ts"], }, }; });