import { existsSync, renameSync, rmSync } from 'node:fs' import { join } from 'node:path' import { fileURLToPath } from 'node:url' import tailwindcss from '@tailwindcss/vite' import react from '@vitejs/plugin-react' import { type Connect, defineConfig, loadEnv, type Plugin } from 'vite' /// 应用前缀 → 入口 HTML,与 lib/service/webapi/src/assets.rs 的 APP_ENTRIES 保持一致。 const APP_ENTRIES: Record = { auth: '/auth/index.html', app: '/app/index.html', } /// dev / preview 下按后端 assets::serve 的规则把子应用路由回落到各自入口。 function mpaFallback(): Plugin { const rewrite = (request: { url?: string }, landing?: string) => { const path = (request.url || '').split('?')[0] if (!path || path === '/') { if (landing) request.url = landing return } if (path.includes('.')) return const first = path.split('/')[1] || '' const entry = APP_ENTRIES[first] if (entry) request.url = entry } const middleware = (landing?: string): Connect.NextHandleFunction => (request, _response, next) => { rewrite(request, landing) next() } return { name: 'mpa-fallback', configureServer(server) { // dev 直接读源码目录,落地页入口在 view/index/index.html。 server.middlewares.use(middleware('/index/index.html')) }, configurePreviewServer(server) { // preview 读 dist,落地页产物已归位到 index.html,无需改写。 server.middlewares.use(middleware()) }, } } /// Vite 按 HTML 相对 root 的路径生成产物;落地页入口在 view/index/ 下,这里归位到 dist/index.html。 function landingOutput(outDir: string): Plugin { return { name: 'landing-output', apply: 'build', closeBundle() { const source = join(outDir, 'index', 'index.html') if (!existsSync(source)) return renameSync(source, join(outDir, 'index.html')) rmSync(join(outDir, 'index'), { recursive: true, force: true }) }, } } export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), '') return { root: 'view', publicDir: 'auth/public', build: { outDir: 'dist', emptyOutDir: true, rollupOptions: { input: { landing: fileURLToPath(new URL('./view/index/index.html', import.meta.url)), auth: fileURLToPath(new URL('./view/auth/index.html', import.meta.url)), app: fileURLToPath(new URL('./view/app/index.html', import.meta.url)), }, }, }, plugins: [ react(), tailwindcss(), mpaFallback(), landingOutput(fileURLToPath(new URL('./view/dist', import.meta.url))), ], resolve: { alias: { '@kenapi/apiclient': fileURLToPath(new URL('./packages/apiclient', import.meta.url)), '@': fileURLToPath(new URL('./view/auth/src', import.meta.url)), }, }, optimizeDeps: { include: ['@noble/hashes/sha2.js'] }, server: { port: 15474, proxy: { '^/api/v1(?:/|$)|^/.well-known/': { target: env.AUTH_API_PROXY || 'http://127.0.0.1:7051', changeOrigin: true, }, }, }, } })