import fs from "node:fs"; import path from "path"; import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; // [nexus] Dev-only middleware that serves onnxruntime-web's wasm files at // /ort-wasm-simd-threaded.{mjs,wasm}. @ricky0123/vad-react sets // `onnxWASMBasePath: "/"`, which makes onnxruntime-web issue dynamic imports // against the site root at runtime. Putting the files in ui/public/ works // at runtime but trips vite's dep optimizer ("files in /public should not // be imported from source code") because it scans onnxruntime-web's dynamic // import and resolves the string to the public asset. This plugin bypasses // public/ entirely — the files never enter vite's module graph, and the URL // is served straight from node_modules. function serveOnnxRuntimeWasm(): import("vite").Plugin { // onnxruntime-web is a transitive dep of @ricky0123/vad-web and not hoisted // to top-level node_modules under pnpm. Scan .pnpm/ for the version dir. const pnpmRoot = path.resolve(__dirname, "../node_modules/.pnpm"); const ortEntry = fs .readdirSync(pnpmRoot) .find((name) => name.startsWith("onnxruntime-web@")); const distDir = ortEntry ? path.join(pnpmRoot, ortEntry, "node_modules/onnxruntime-web/dist") : null; return { name: "nexus-serve-onnxruntime-wasm", configureServer(server) { if (!distDir) { server.config.logger.warn( "[nexus-serve-onnxruntime-wasm] onnxruntime-web not found in .pnpm store — VAD voice input will 404", ); return; } server.middlewares.use((req, res, next) => { const url = (req.url ?? "").split("?")[0]; const match = url.match(/^\/ort-wasm-simd-threaded\.(mjs|wasm)$/); if (!match) return next(); const filePath = path.join(distDir, `ort-wasm-simd-threaded.${match[1]}`); fs.readFile(filePath, (err, content) => { if (err) { next(err); return; } res.setHeader( "Content-Type", match[1] === "mjs" ? "text/javascript" : "application/wasm", ); res.end(content); }); }); }, }; } // [nexus] Redirect OnboardingWizard → NexusOnboardingWizard at resolve time. // A Vite plugin is used instead of resolve.alias because alias matches against // the raw import specifier ("./components/OnboardingWizard") — not the resolved // absolute path — so an absolute-path alias key never fires. function nexusOnboardingRedirect(): import("vite").Plugin { const target = path.resolve(__dirname, "./src/components/NexusOnboardingWizard.tsx"); return { name: "nexus-onboarding-redirect", enforce: "pre", resolveId(source) { if (source.endsWith("/components/OnboardingWizard") && !source.includes("Nexus")) { return target; } }, }; } export default defineConfig({ plugins: [nexusOnboardingRedirect(), serveOnnxRuntimeWasm(), react(), tailwindcss()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), lexical: path.resolve(__dirname, "./node_modules/lexical/Lexical.mjs"), }, }, build: { rollupOptions: { output: { manualChunks: { // Note: react/react-dom cannot be split via manualChunks — @vitejs/plugin-react // injects the JSX runtime before Rollup processes chunks, so they stay in the entry. // The 37 lazy-loaded page chunks are the primary performance lever. "vendor-router": ["react-router-dom"], "vendor-query": ["@tanstack/react-query"], "vendor-markdown": ["react-markdown", "remark-gfm"], }, }, }, }, server: { port: 5173, // COOP/COEP headers are only respected over HTTPS or localhost. // Omitted so LAN access (plain HTTP + non-localhost IP) doesn't trigger // browser warnings. Re-enable when serving behind TLS. // headers: { // "Cross-Origin-Opener-Policy": "same-origin", // "Cross-Origin-Embedder-Policy": "require-corp", // }, proxy: { "/api": { target: "http://localhost:6100", ws: true, }, }, }, });