Files
admin-ui/vite.config.js
2026-08-28 05:24:30 +08:00

153 lines
4.7 KiB
JavaScript

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 = `<script>window.ADMIN_UI_BASE_PATH="${escaped}";</script>`;
return html.replace('</head>', `${tag}</head>`);
},
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,
},
};
});