Files
open-gateway-front/vite.config.ts
T

169 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ConfigEnv, UserConfig, defineConfig, type Plugin } from "vite";
import { createHtmlPlugin } from "vite-plugin-html";
import vue from "@vitejs/plugin-vue";
import path, { resolve } from "path";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import ViteAutoImport from "unplugin-auto-import/vite";
import UnoCSS from "@unocss/vite";
import presetUno from "@unocss/preset-uno";
import presetRemToPx from "@unocss/preset-rem-to-px";
// mock 数据层(仅 --mode mock 注册,见下方 gatewayAdminMockPlugin;零依赖手写中间件而非
// vite-plugin-mock:后者独立打包 mock 文件为第二模块实例,无法实现"整页刷新重置内存态")
import { handleGatewayMockRequest, resetGatewayMockState } from "./src/assets/mock/gatewayApi";
/** 内置 mock(仅 serve + --mode mock):拦截 /open-gateway/api/internal/** 按后端契约应答。
* 直接注册在 configureServer(先于 vite 内部中间件,含 /open-gateway/api 代理);
* 整页文档请求(刷新/直达)触发内存态重置回静态种子,SPA 站内切换不重置。 */
function gatewayAdminMockPlugin(): Plugin {
return {
name: "gateway-admin-mock",
apply: "serve",
configureServer(server) {
server.middlewares.use((req, _res, next) => {
const accept = String(req.headers.accept ?? "");
if (accept.includes("text/html")) resetGatewayMockState();
next();
});
server.middlewares.use(async (req, res, next) => {
try {
if (!(await handleGatewayMockRequest(req, res))) next();
} catch (e) {
next(e);
}
});
},
};
}
// 构建输出恒为 dist 根:CI 打包 zip 的根目录必须直接是 index.html(projman 前端发布校验 zip 根含 html)。
// 不再有 dist/base 中间层——outDir=dist/base 时 zip 打 dist 整层,zip 根只有 base/,发布会校验失败。
// dev(--mode dev)读 .env.dev,VITE_SERVICE_HOST 指向同源前缀 /open-gateway(经下方 proxy 打到 base 域)
export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
const outDir = "dist";
return {
plugins: [
// 仅 --mode mock 启用内置 mock;dev/联调/正式 build 行为零变化
...(mode === "mock" ? [gatewayAdminMockPlugin()] : []),
vue(),
createSvgIconsPlugin({
iconDirs: [resolve(process.cwd(), "src/assets/icons")],
symbolId: "icon-[dir]-[name]",
inject: "body-last",
customDomId: "__svg__icons__dom__",
}),
ViteAutoImport({
imports: [
"vue",
"vue-router",
{
"view-ui-plus": ["Button", "Table", "Modal", "Message", "Form", "FormItem", "Input", "Select"],
},
{
from: "alova/client",
imports: ["usePagination", "useRequest", "useWatcher", "useForm"],
},
],
dts: "./src/auto-imports.d.ts",
dirs: ["src/api"],
}),
createHtmlPlugin({
minify: true,
pages: [
{
entry: "src/main.ts",
template: "index.html",
filename: "index.html",
injectOptions: {
data: {
title: "开放网关",
injectScript: ``,
},
},
},
],
}),
UnoCSS({
presets: [
presetUno(),
presetRemToPx({ baseFontSize: 4 }), // 1单位=1px(去rem化)
],
shortcuts: {
"flex-center": "flex items-center justify-center",
btn: "px-16px py-8px rounded-4px cursor-pointer transition-all duration-200",
"btn-primary": "bg-blue-600 text-white hover:bg-blue-700",
card: "bg-white rounded-8px shadow-md p-16px",
"text-ellipsis": "truncate",
"text-multi-ellipsis": "line-clamp-2",
},
theme: {
fontSize: {
xs: "12px",
sm: "14px",
base: "16px",
lg: "18px",
xl: "20px",
"2xl": "24px",
},
},
}),
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
host: "localhost",
port: 8131,
// 本地联调:/open-gateway/api/* → base 域(Caddy 剥前缀后转发到网关容器网内 10013)
// 走代理而非跨源直连:网关无 CORS,且 10013 仅绑容器网内 127.0.0.1
proxy: {
"/open-gateway/api": {
target: "http://base.yunhaixingtong.com",
changeOrigin: true,
},
// 主题通道本地联调(照 Notice 配方):index.html loader 走同源相对 /static/js/yh-theme-init.js,
// manifest/CSS 经此代理到中央通道;base 域不可达(无 VPN)时由 npm run dev:mock
// (scripts/start-mock.mjs)以 YH_THEME_PROXY_TARGET 把目标覆盖为本地 9527 静态服务。
"/static": {
target: process.env.YH_THEME_PROXY_TARGET || "http://base.yunhaixingtong.com",
changeOrigin: true,
},
},
},
base: "./",
build: {
target: "modules",
outDir,
assetsDir: "assets",
sourcemap: false,
minify: "esbuild",
chunkSizeWarningLimit: 1000,
cssTarget: "chrome61",
rollupOptions: {
input: {
main: resolve("index.html"),
},
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: (assetInfo: any) => {
if (assetInfo.type === "asset" && /\.(jpe?g|png|gif|svg)$/i.test(assetInfo.name)) {
return "static/img/[name].[hash][ext]";
}
if (assetInfo.type === "asset" && /\.(ttf|woff|woff2|eot)$/i.test(assetInfo.name)) {
return "static/fonts/[name].[hash][ext]";
}
return "static/[ext]/[name]-[hash].[ext]";
},
},
manualEntrypoint: "index.html",
},
},
};
});