import fs from "fs"; import path from "path"; import react from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; import { defineConfig, loadEnv } from "vite"; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ""); // Same-origin sub-path the host server serves the module from. `base` makes // built asset URLs resolve under it AND is read back inside the module // (import.meta.env.BASE_URL) to set the router basename. Override with UM_BASE. const base = env.UM_BASE || "/_um/"; // Build straight into the host app's public dir so its ONE server serves the // module at /_um/ — no second server, same origin as the host. const outDir = path.resolve(__dirname, "../apps/backoffice/public/_um"); return { base, plugins: [ tailwindcss(), react(), { // TinyMCE is self-hosted; the module references it at the ABSOLUTE path // /tinymce/..., which resolves at the host origin. Mirror the assets into // BOTH the module public dir AND the host public root. Regenerated on // build, so neither copy is a hand-managed artifact. name: "copy-tinymce-assets", buildStart() { const src = path.resolve(__dirname, "node_modules/tinymce"); const dests = [ path.resolve(__dirname, "../user-management/public/tinymce"), path.resolve(__dirname, "../apps/backoffice/public/tinymce"), ]; const runtimeEntries = [ "tinymce.min.js", "icons", "models", "plugins", "skins", "themes", ]; if (!fs.existsSync(src)) { throw new Error( "[copy-tinymce-assets] node_modules/tinymce not found in this app. Run `npm install` here first." ); } for (const dest of dests) { fs.mkdirSync(dest, { recursive: true }); for (const entry of runtimeEntries) { const entrySrc = path.resolve(src, entry); const entryDest = path.resolve(dest, entry); if (!fs.existsSync(entrySrc)) continue; fs.cpSync(entrySrc, entryDest, { recursive: true, force: true }); } } }, }, ], assetsInclude: ["**/*.TTF"], // Static assets (incl. tinymce/) live in the module's public dir. publicDir: path.resolve(__dirname, "../user-management/public"), build: { rollupOptions: { external: [ "file-type", "readable-web-to-node-stream", "strtok3", "token-types", ], }, outDir, assetsDir: "assets", sourcemap: false, emptyOutDir: true, minify: "esbuild", }, resolve: { alias: [ // @app-config = this host folder itself (project.theme.ts / fhc.theme.ts). { find: /^@app-config\//, replacement: path.resolve(__dirname) + "/" }, // @/ = the reusable module's source in the SIBLING module folder. { find: /^@\//, replacement: path.resolve(__dirname, "../user-management/src") + "/" }, ], // node_modules is linked to the module's, but pin the singletons so the host // entry and the module code share ONE React 18 (no "invalid hook call"). dedupe: ["react", "react-dom", "react-router-dom", "@tanstack/react-query", "@mantine/core", "@mantine/hooks"], }, server: { port: env.DEV_PORT ? Number(env.DEV_PORT) : 5173, strictPort: true, fs: { allow: [path.resolve(__dirname, "..")] }, }, optimizeDeps: { exclude: ["file-type", "readable-web-to-node-stream", "strtok3", "token-types"], }, esbuild: { drop: mode === "production" ? ["console", "debugger"] : [], }, define: { global: {}, }, }; });