import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import wasm from "vite-plugin-wasm"; import { loadBasePath } from "./src/server/config.js"; import { basePathHref } from "./src/shared/basePath.js"; import { pdfjsCmaps } from "./scripts/pdfjs-cmaps.js"; import { pdfjsViewerCompatibility } from "./scripts/pdfjs-viewer.js"; import { precompressAssets } from "./scripts/precompress-assets.js"; function developmentHtmlBase(basePath: string) { const href = basePathHref(basePath); return { name: "texlite-development-base-path", transformIndexHtml(html: string) { return html .replace(//i, ``) .replace(//i, ``); } }; } export default defineConfig(({ command }) => { // Production uses relative asset URLs so one package build can be mounted // at any runtime server.basePath. During development, read the exact same // configuration as the API server so Vite serves and proxies that prefix. const developmentBasePath = command === "serve" ? loadBasePath() : "/"; const developmentBaseHref = basePathHref(developmentBasePath); const apiPrefix = `${developmentBasePath === "/" ? "" : developmentBasePath}/api/`; return { base: command === "serve" ? developmentBaseHref : "./", plugins: [developmentHtmlBase(developmentBasePath), pdfjsCmaps(), pdfjsViewerCompatibility(), react(), wasm(), precompressAssets()], optimizeDeps: { // Keep the viewer in the plugin pipeline in development as well as builds. exclude: ["pdfjs-dist/web/pdf_viewer.mjs"], // This dependency is only imported by a Worker, so the initial scan // misses it. Pre-bundle it to avoid reloading the page on first format. include: ["tex-fmt"] }, worker: { // Worker bundles use their own plugin pipeline. tex-fmt is deliberately // loaded there so both its WASM execution and diff calculation stay off // the editor's main thread. plugins: () => [wasm()], format: "es" }, root: "src/client", build: { // tex-fmt's WASM module uses native top-level await. TexLite targets // current browsers, so retaining it avoids a fragile post-build rewrite. target: "esnext", outDir: "../../dist/client", emptyOutDir: true, rolldownOptions: { output: { // Keep heavy editor/PDF modules behind their existing lazy imports. // Only React's core runtime belongs in the initial shared chunk; // react-* feature packages retain their own route boundaries. codeSplitting: { groups: [ // Vite's shared preload helper must not be captured recursively // by the PDF group, which would eagerly load PDF.js on login. { name: "vite-runtime", test: /\0vite\/.*helper/, priority: 10 }, { name: "pdf-viewer", test: /[\\/]node_modules[\\/]pdfjs-dist[\\/]web[\\/]/, priority: 5, includeDependenciesRecursively: false }, { name: "pdf", test: /[\\/]node_modules[\\/]pdfjs-dist[\\/]/ }, // Keep generic text languages separate from CodeMirror's core. // Do not pull their shared core dependencies into this group. { name: "editor-languages", test: /[\\/]node_modules[\\/](?:@codemirror[\\/](?:lang-[^\\/]+|legacy-modes)|@lezer[\\/](?:css|html|javascript|json|markdown|python|xml|yaml))[\\/]/, priority: 5, includeDependenciesRecursively: false }, { name: "editor", test: /[\\/]node_modules[\\/](?:@codemirror|@lezer)[\\/]/ }, { name: "react", test: /[\\/]node_modules[\\/](?:react|react-dom|scheduler)[\\/]/ } ] } } } }, server: { host: "127.0.0.1", port: 5173, proxy: { [apiPrefix]: { target: `http://127.0.0.1:${process.env.TEXLITE_DEV_SERVER_PORT ?? "3000"}`, ws: true } } } }; });