import { defineConfig, loadEnv } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'node:path'; const projectRoot = import.meta.dirname; const outDir = path.resolve(projectRoot, 'dist'); function normalizeBasePath(value) { const trimmed = String(value || '/').trim(); const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`; return withLeadingSlash.endsWith('/') ? withLeadingSlash : `${withLeadingSlash}/`; } function rewritePageRequest(request, basePath) { if (request.method !== 'GET' || !request.url) return; const [pathname, query = ''] = request.url.split('?'); const suffix = query ? `?${query}` : ''; const panelPath = `${basePath}panel`.replace(/\/+/g, '/'); const apiPath = `${panelPath}/api`; if (pathname === basePath || pathname === basePath.slice(0, -1)) { request.url = `/login.html${suffix}`; return; } if ( pathname !== apiPath && !pathname.startsWith(`${apiPath}/`) && (pathname === panelPath || pathname.startsWith(`${panelPath}/`)) ) { request.url = `/index.html${suffix}`; } } function adminPagesPlugin(basePath) { const configure = (server) => { server.middlewares.use((request, _response, next) => { rewritePageRequest(request, basePath); next(); }); }; return { name: 'admin-ui-pages', apply: 'serve', transformIndexHtml(html) { const escaped = basePath.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); const tag = ``; return html.replace('', `${tag}`); }, configureServer: configure, configurePreviewServer: configure, }; } function createProxy(backendTarget) { if (!backendTarget) return undefined; return { '^/(?:[^/]+/)?(?:login|logout|getTwoFactorEnable|csrf-token|panel/api)(?:/|$)': { target: backendTarget, changeOrigin: true, }, }; } export default defineConfig(({ mode }) => { const env = loadEnv(mode, projectRoot, ''); const basePath = normalizeBasePath(env.VITE_ADMIN_BASE_PATH); const backendTarget = env.VITE_BACKEND_TARGET?.trim(); return { plugins: [react(), adminPagesPlugin(basePath)], resolve: { alias: { '@': path.resolve(projectRoot, 'src'), }, }, experimental: { renderBuiltUrl(filename, { hostType }) { if (hostType === 'js') { return { runtime: `((window.ADMIN_UI_BASE_PATH||'/')+${JSON.stringify(filename)})`, }; } return undefined; }, }, build: { outDir, emptyOutDir: true, sourcemap: env.VITE_SOURCEMAP === 'true', target: 'es2020', chunkSizeWarningLimit: 1500, rollupOptions: { input: { index: path.resolve(projectRoot, 'index.html'), login: path.resolve(projectRoot, 'login.html'), }, output: { manualChunks(id) { if (!id.includes('node_modules')) return undefined; if (id.includes('/node_modules/antd/')) return 'vendor-antd'; if (id.includes('/@ant-design/icons/') || id.includes('/@ant-design/icons-svg/')) { return 'vendor-icons'; } if ( id.includes('/node_modules/@rc-component/') || id.includes('/node_modules/rc-') || id.includes('/@ant-design/cssinjs') || id.includes('/@ant-design/colors') || id.includes('/@ant-design/fast-color') || id.includes('/@ant-design/react-slick') || id.includes('/@ctrl/tinycolor') ) { return 'vendor-antd'; } if ( id.includes('/node_modules/react-i18next/') || id.includes('/node_modules/i18next/') ) { return 'vendor-i18next'; } if ( id.includes('/node_modules/react/') || id.includes('/node_modules/react-dom/') || id.includes('/node_modules/scheduler/') ) { return 'vendor-react'; } if (id.includes('/node_modules/@tanstack/')) return 'vendor-tanstack'; if (id.includes('/node_modules/react-hook-form/')) return 'vendor-react-hook-form'; if (id.includes('/node_modules/react-router')) return 'vendor-router'; if (id.includes('/node_modules/dayjs/')) return 'vendor-dayjs'; return 'vendor'; }, }, }, }, server: { host: '0.0.0.0', port: 19999, strictPort: true, proxy: createProxy(backendTarget), }, preview: { host: '0.0.0.0', port: 19999, strictPort: true, }, }; });