import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' const chunkSizeWarningLimit = 850 function chunkGroup(id: string) { const normalizedId = id.replaceAll('\\', '/') if (normalizedId.includes('/node_modules/')) { // Heavy, self-contained leaf libs (no Vue import) — isolate so they don't // bloat the main vendor chunk. Pure parsers, zero cross-chunk init-order risk. if (normalizedId.includes('/node_modules/pdfjs-dist/')) { return 'vendor-pdfjs' } if (normalizedId.includes('/node_modules/xlsx/')) { return 'vendor-xlsx' } if (normalizedId.includes('/node_modules/mammoth/')) { return 'vendor-mammoth' } // Element Plus + its icons depend on Vue one-way (no circular) — proven safe // to keep as their own cacheable chunks. if (normalizedId.includes('/node_modules/@element-plus/icons-vue/')) { return 'vendor-element-icons' } if (normalizedId.includes('/node_modules/element-plus/')) { return 'vendor-element-plus' } // vue + @vue + EVERY Vue-coupled lib (tiptap / prosemirror / yjs / // vuedraggable / sortablejs ...) MUST share one chunk. Splitting Vue into its // own `vendor-vue` chunk let those libs evaluate before Vue finished // initializing, throwing a cross-chunk TDZ at runtime: // "ReferenceError: Cannot access 'W' before initialization" → blank page. // Circular deps WITHIN a single chunk are hoisted correctly by Rollup. return 'vendor' } if (normalizedId.includes('/src/components/erp/ErpPageRenderer.vue')) { return 'erp-page-renderer' } if (normalizedId.includes('/src/components/erp/')) { return 'erp-components' } } export default defineConfig({ plugins: [vue()], base: '/', server: { port: 5175, proxy: { // OA backend (Java / Spring Boot). All OA calls live under /api/oa/*. // Proxying keeps the browser same-origin in dev, so no CORS is needed. '/api': { target: 'http://localhost:8090', changeOrigin: true, secure: false }, // Real-time collaboration WebSocket (yjs CRDT relay). ws:true upgrades the // connection so /ws/collab/{docId} reaches the backend in dev too. '/ws': { target: 'ws://localhost:8090', ws: true, changeOrigin: true } } }, build: { // Single-deployable: build straight into the Spring Boot backend's static // resources, so `gradlew bootJar` then bundles the SPA into the one runnable jar // (served on the same port as the API — no separate vite / proxy / CORS). outDir: '../../../../oa-backend/src/main/resources/static', assetsDir: 'assets', emptyOutDir: true, chunkSizeWarningLimit, rollupOptions: { output: { manualChunks: chunkGroup } } } })