import { existsSync } from "node:fs"; import { createRequire } from "node:module"; import { dirname, join } from "node:path"; import { fileURLToPath, URL } from "node:url"; import { defineConfig, type Plugin } from "vite"; import react from "@vitejs/plugin-react"; const require = createRequire(import.meta.url); const webuiRoot = dirname(fileURLToPath(import.meta.url)); const installedModulesVirtualId = "virtual:govoplan-installed-modules"; const resolvedInstalledModulesVirtualId = `\0${installedModulesVirtualId}`; const installedModuleVirtualPrefix = "virtual:govoplan-installed-module/"; const resolvedInstalledModuleVirtualPrefix = `\0${installedModuleVirtualPrefix}`; const defaultWebModulePackages = [ "@govoplan/access-webui", "@govoplan/admin-webui", "@govoplan/addresses-webui", "@govoplan/audit-webui", "@govoplan/calendar-webui", "@govoplan/campaign-webui", "@govoplan/dataflow-webui", "@govoplan/datasources-webui", "@govoplan/dashboard-webui", "@govoplan/docs-webui", "@govoplan/files-webui", "@govoplan/idm-webui", "@govoplan/mail-webui", "@govoplan/notifications-webui", "@govoplan/organizations-webui", "@govoplan/ops-webui", "@govoplan/policy-webui", "@govoplan/postbox-webui", "@govoplan/risk-compliance-webui", "@govoplan/scheduling-webui", "@govoplan/search-webui", "@govoplan/views-webui", "@govoplan/workflow-webui" ]; function configuredWebModulePackages(): string[] { const configured = process.env.GOVOPLAN_WEBUI_MODULE_PACKAGES; if (configured === undefined) return defaultWebModulePackages; return configured.split(",").map((specifier) => specifier.trim()).filter(Boolean); } function packageDirectory(specifier: string): string { const parts = specifier.startsWith("@") ? specifier.split("/") : [specifier]; return join(webuiRoot, "node_modules", ...parts); } function packageInstalled(specifier: string): boolean { if (existsSync(join(packageDirectory(specifier), "package.json"))) return true; try { require.resolve(specifier); return true; } catch { return false; } } function availableWebModuleSpecifiers(): string[] { return configuredWebModulePackages().filter(packageInstalled); } function govoplanInstalledModulesPlugin(): Plugin { const specifierByModuleVirtualId = new Map( availableWebModuleSpecifiers().map((specifier) => [ `${installedModuleVirtualPrefix}${encodeURIComponent(specifier)}`, specifier ]) ); return { name: "govoplan-installed-modules", resolveId(id: string) { if (id === installedModulesVirtualId) return resolvedInstalledModulesVirtualId; if (specifierByModuleVirtualId.has(id)) return `\0${id}`; return null; }, load(id: string) { if (id === resolvedInstalledModulesVirtualId) { const loaders = [...specifierByModuleVirtualId].map(([virtualId, specifier]) => ( `{ packageName: ${JSON.stringify(specifier)}, load: () => import(${JSON.stringify(virtualId)}) }` )); return [ `export const installedWebModuleLoaders = [${loaders.join(", ")}];`, "export default installedWebModuleLoaders;" ].join("\n"); } if (!id.startsWith(resolvedInstalledModuleVirtualPrefix)) return null; const publicVirtualId = id.slice(1); const specifier = specifierByModuleVirtualId.get(publicVirtualId); if (!specifier) return null; const moduleEntry = join(packageDirectory(specifier), "src", "module.ts"); if (!existsSync(moduleEntry)) { throw new Error(`${specifier} does not expose src/module.ts`); } // Import the contribution descriptor directly. Package root barrels may // intentionally re-export pages and would otherwise defeat route splitting. return `export { default } from ${JSON.stringify(moduleEntry)};`; } }; } export default defineConfig({ plugins: [govoplanInstalledModulesPlugin(), react()], optimizeDeps: { exclude: availableWebModuleSpecifiers(), // Dataflow is discovered through the virtual module registry, so Vite's // initial scan cannot see this CommonJS-backed transitive dependency. include: ["@xyflow/react"] }, build: { manifest: true, chunkSizeWarningLimit: 500 }, resolve: { preserveSymlinks: false, dedupe: [ "@xyflow/react", "lucide-react", "react", "react-dom", "react-router-dom", "read-excel-file" ], alias: [ { find: "@govoplan/core-webui/app", replacement: fileURLToPath(new URL("./src/app.ts", import.meta.url)) }, { find: "@govoplan/core-webui/definition-graph", replacement: fileURLToPath(new URL("./src/definitionGraph.ts", import.meta.url)) }, { find: "@govoplan/core-webui", replacement: fileURLToPath(new URL("./src/index.ts", import.meta.url)) } ] }, server: { fs: { allow: [ fileURLToPath(new URL('.', import.meta.url)), fileURLToPath(new URL('../../govoplan-access/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-admin/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-addresses/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-audit/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-calendar/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-dataflow/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-datasources/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-dashboard/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-docs/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-files/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-idm/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-mail/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-notifications/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-organizations/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-campaign/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-ops/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-policy/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-postbox/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-risk-compliance/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-scheduling/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-search/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-views/webui', import.meta.url)), fileURLToPath(new URL('../../govoplan-workflow/webui', import.meta.url)) ] }, proxy: { "/api": { target: process.env.VITE_API_PROXY_TARGET || "http://127.0.0.1:8000", changeOrigin: true }, "/health": { target: process.env.VITE_API_PROXY_TARGET || "http://127.0.0.1:8000", changeOrigin: true } } } });