Files
govoplan-core/webui/vite.config.ts

175 lines
6.9 KiB
TypeScript

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
}
}
}
});