Skyroc Admin 的 Vite 配置预设包 — 收口构建产物、开发代理、路由插件、React 插件、图标插件、自动导入、别名与开发服务器默认配置
@skyroc/web-admin-vite 是 Skyroc Admin 应用的 Vite 预设层。它的目标不是替代 Vite,而是把管理后台项目中高度重复、且容易在不同应用之间漂移的配置沉淀成共享入口。
它主要负责:
build 输出规则,包括 CSS、图片、页面 chunk、组件 chunk 和基础 vendor chunkapplication 级预设配置,同时保留 vite 字段作为原生 Vite 配置覆盖层应用层应尽量保持 vite.config.ts 简洁,只描述本应用的差异;共享规则放在 @skyroc/web-admin-vite 内维护。
当一个管理后台应用符合下面约定时,推荐直接使用该预设:
src/pages@ 指向 src,~ 指向应用根目录src/assets/svg-icon.env 中的 VITE_* 变量配置 base url、代理开关和后端服务地址如果应用只需要少量差异,优先通过 application 覆盖预设;只有必须使用 Vite 原生能力时,再使用 vite 字段。
apps/admin/vite.config.ts
│
└─ import { defineConfig } from '@skyroc/web-admin-vite'
│
▼
packages/web/admin-vite/src/config.ts
├─ loadEnv() 读取应用环境变量
├─ createAdminApplicationConfig() 生成 admin preset Vite 配置
├─ setupAdminVitePlugins() 生成内置插件组
└─ mergeConfig(adminConfig, vite) 合并原始 Vite 覆盖配置
│
▼
Vite runtime包内职责划分:
src/
├── config.ts defineConfig 主入口,负责应用级配置编排
├── build.ts 构建产物命名、manual chunks、SCSS preprocessor
├── proxy.ts 服务配置解析与 Vite dev proxy 创建
├── time.ts BUILD_TIME 生成
├── types.ts 图标配置、插件插槽、公共配置类型
└── plugins/
├── index.ts 内置插件顺序与开关
├── router.ts TanStack Router 插件默认配置
├── react.ts @vitejs/plugin-react
├── babel.ts Jotai preset + React Compiler preset
├── unocss.ts UnoCSS icon preset
├── unplugin-icon.ts unplugin-icons + svg sprite
├── auto-import.ts React / i18n / ahooks / AntD / icon 自动导入
├── html.ts buildTime meta 注入
├── info.ts 终端项目提示
└── icon-utils.ts 图标前缀、集合名、本地图标路径统一解析最常见的应用配置只需要声明 SCSS 全局注入:
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig({
application: {
css: {
additionalData: '@use "@/styles/scss/global.scss" as *;'
}
}
});如果完全接受默认预设,可以进一步简化:
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig();需要根据 Vite 命令或 mode 动态配置时,传入工厂函数:
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig(configEnv => {
return {
application: {
base: configEnv.mode === 'prod' ? '/admin/' : '/'
}
};
});defineConfig 支持三种写法:
defineConfig();
defineConfig({ application: {}, vite: {} });
defineConfig(configEnv => ({ application: {}, vite: {} }));完整结构:
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig({
application: {
// Skyroc Admin preset options
},
vite: {
// 原始 Vite UserConfig,在 admin preset 之后 merge
}
});application 是推荐配置面,描述后台应用预设差异。vite 是逃生口,用于补充或覆盖 Vite 原生配置。
这个包刻意没有把 Vite 原生 options 平铺到最外层,而是分成两层:
| 字段 | 职责 | 示例 |
|---|---|---|
application | Skyroc Admin 预设语义,用来描述后台应用的差异 | plugins.projectInfo: false、proxy.enabled、buildTimeDefineName、css.additionalData |
vite | Vite 原生 UserConfig,作为最终覆盖层 | optimizeDeps、server.fs、resolve.conditions、第三方 Vite 配置 |
这样设计是为了避免字段语义冲突。比如 plugins、build、server、resolve 这些名字在 Vite 里本来就存在,但本包也需要提供 admin 语义:
export default defineConfig({
application: {
plugins: {
router: false,
autoImport: {
antd: false
}
},
build: {
manualChunks: {
charts: ['echarts']
}
}
},
vite: {
server: {
fs: {
strict: false
}
}
}
});如果允许这样平铺:
export default defineConfig({
plugins: [],
build: {},
server: {}
});plugins 就无法清楚表达它到底是 Vite 的 PluginOption[],还是 admin preset 的插件开关对象;build 也会同时像 Vite 的 BuildOptions 和 admin 的构建预设配置。长期看,这会让 API 既不像 Vite,也不像 admin preset。
因此推荐规则是:
applicationvitevite 最后合并,优先级更高application.xxx = false 关闭,再在 vite 里补原生配置defineConfig 默认会生成这些配置:
| 配置项 | 默认行为 |
|---|---|
base | 优先使用 application.base,否则读取 VITE_BASE_URL,再否则为 / |
build | 使用 admin 构建产物命名和基础 manual chunks |
define | 注入 BUILD_TIME |
css | 按需注入 SCSS additionalData |
plugins | 启用 admin 内置插件组 |
preview | 默认端口 9725 |
resolve | 默认 @ -> src、~ -> .,并 dedupe React runtime |
server | 默认 host = 0.0.0.0、open = true、port = 9527 |
proxy | 开发服务下根据环境变量创建代理 |
环境变量只负责应用运行和代理相关配置,不再负责图标插件前缀。图标前缀通过插件 options 配置。
| 变量名 | 作用 |
|---|---|
VITE_BASE_URL | 应用 base url |
VITE_HTTP_PROXY | 为 Y 时,在 dev server 中启用代理 |
VITE_PROXY_LOG | 为 Y 时,打印代理请求日志 |
VITE_SERVICE_BASE_URL | 默认后端服务地址 |
VITE_OTHER_SERVICE_BASE_URL | 其他后端服务地址,支持 JSON5 字符串 |
示例:
VITE_BASE_URL=/
VITE_HTTP_PROXY=Y
VITE_PROXY_LOG=Y
VITE_SERVICE_BASE_URL=https://api.example.com
VITE_OTHER_SERVICE_BASE_URL={ auth: "https://auth.example.com" }默认代理路径:
| 服务 | 代理前缀 |
|---|---|
| 主服务 | /proxy-default |
| 其他服务 | /proxy-${key} |
例如:
VITE_OTHER_SERVICE_BASE_URL={ auth: "https://auth.example.com" }会创建:
/proxy-auth -> https://auth.example.com默认 root 是当前命令执行目录,envDir 默认跟随 root。
export default defineConfig({
application: {
root: process.cwd(),
envDir: process.cwd()
}
});一般应用不需要配置这两项。只有当 Vite 命令执行目录和应用目录不一致时才需要显式指定。
配置应用 base url。支持静态值,也支持根据上下文动态返回。
export default defineConfig({
application: {
base: '/admin/'
}
});export default defineConfig({
application: {
base: context => (context.isBuild ? '/admin/' : '/')
}
});配置函数可读取的上下文:
| 字段 | 说明 |
|---|---|
buildTime | 当前配置加载时生成的构建时间 |
configEnv | Vite 传入的 ConfigEnv |
env | loadEnv() 读取到的环境变量 |
isBuild | 当前是否是 vite build |
isPreview | 当前是否是 preview |
isServe | 当前是否是 dev server |
root | 当前应用根目录 |
配置 SCSS 全局注入:
export default defineConfig({
application: {
css: {
additionalData: '@use "@/styles/scss/global.scss" as *;'
}
}
});也可以根据环境动态返回:
export default defineConfig({
application: {
css: {
additionalData: context => {
return context.isBuild ? '@use "@/styles/scss/global.scss" as *;' : '@use "@/styles/scss/dev.scss" as *;';
}
}
}
});关闭 CSS 预设:
export default defineConfig({
application: {
css: false
}
});默认构建规则:
css/[name]-[hash].cssimages/[name]-[hash].[ext]js/pages/**/[name]-[hash].jsjs/components/[name]-[hash].jsjs/[name]-[hash].jsreact、antd、react-router、il8n追加 manual chunks:
export default defineConfig({
application: {
build: {
manualChunks: {
charts: ['echarts'],
query: ['@tanstack/react-query']
}
}
}
});调整路径识别规则:
export default defineConfig({
application: {
build: {
componentsDirPattern: '/src/shared/components/',
pagesDirPattern: '/src/routes/'
}
}
});关闭 build 预设:
export default defineConfig({
application: {
build: false
}
});默认 dev server:
{
host: '0.0.0.0',
open: true,
port: 9527,
warmup: {
clientFiles: ['./index.html', './src/{pages,components}/*']
}
}覆盖配置:
export default defineConfig({
application: {
server: {
open: false,
port: 3000,
warmupClientFiles: ['./index.html', './src/pages/**/*']
}
}
});关闭 server 预设:
export default defineConfig({
application: {
server: false
}
});默认 preview 端口为 9725:
export default defineConfig({
application: {
preview: {
port: 4173
}
}
});关闭 preview 预设:
export default defineConfig({
application: {
preview: false
}
});默认代理启用条件:
serveVITE_HTTP_PROXY=Y手动控制:
export default defineConfig({
application: {
proxy: {
enabled: context => context.isServe && !context.isPreview,
enableLog: true
}
}
});自定义服务配置:
export default defineConfig({
application: {
proxy: {
serviceConfig: {
baseURL: 'https://api.example.com',
proxyPattern: '/api',
other: [
{
baseURL: 'https://auth.example.com',
proxyPattern: '/auth-api'
}
]
}
}
}
});关闭代理预设:
export default defineConfig({
application: {
proxy: false
}
});默认别名:
| 别名 | 指向 |
|---|---|
@ | src |
~ | 应用根目录 |
默认 dedupe:
['react', 'react-dom', 'react/jsx-dev-runtime', 'react/jsx-runtime'];覆盖别名:
export default defineConfig({
application: {
resolve: {
rootAlias: false,
srcAlias: 'source'
}
}
});关闭 React dedupe:
export default defineConfig({
application: {
resolve: {
dedupeReact: false
}
}
});关闭 resolve 预设:
export default defineConfig({
application: {
resolve: false
}
});默认会注入:
define: {
BUILD_TIME: JSON.stringify(buildTime);
}默认时间格式为 YYYY-MM-DD HH:mm:ss,默认时区为 Asia/Shanghai。
修改格式:
export default defineConfig({
application: {
buildTime: {
format: 'YYYY-MM-DD HH:mm',
timezone: 'Asia/Shanghai'
}
}
});修改注入变量名:
export default defineConfig({
application: {
buildTimeDefineName: '__BUILD_TIME__'
}
});关闭构建时间注入:
export default defineConfig({
application: {
buildTimeDefineName: false
}
});默认插件顺序:
prependPluginsappendPlugins每个内置插件都支持两种配置方式:
plugins: {
inspect: false, // 关闭
projectInfo: { // 传 options
enabled: false
}
}prependPlugins 插入在所有内置插件之前,appendPlugins 插入在所有内置插件之后。
import type { Plugin } from 'vite';
import { defineConfig } from '@skyroc/web-admin-vite';
const myPlugin: Plugin = {
name: 'my-plugin'
};
export default defineConfig({
application: {
plugins: {
prependPlugins: [myPlugin]
}
}
});传给 @vitejs/plugin-react:
export default defineConfig({
application: {
plugins: {
react: {
jsxRuntime: 'automatic'
}
}
}
});关闭 React 插件:
export default defineConfig({
application: {
plugins: {
react: false
}
}
});Babel 插件默认包含:
jotai-babel/presetreactCompilerPreset()调整配置:
export default defineConfig({
application: {
plugins: {
babel: {
jotai: false,
reactCompiler: false
}
}
}
});关闭 Babel:
export default defineConfig({
application: {
plugins: {
babel: false
}
}
});默认 TanStack Router 配置:
| 选项 | 默认值 |
|---|---|
routesDirectory | ./src/pages |
generatedRouteTree | ./src/features/router/routeTree.gen.ts |
routeFileIgnorePattern | 忽略 components、modules、loading、error、not-found |
routeToken | layout |
target | react |
autoCodeSplitting | true |
覆盖路由目录:
export default defineConfig({
application: {
plugins: {
router: {
routesDirectory: './src/routes'
}
}
}
});三个插件共享同一套图标解析规则:
unocss: 生成 icon classunpluginIcon: 生成 icon React component 与本地 svg spriteautoImport: 自动导入 icon component默认图标配置:
| 选项 | 默认值 |
|---|---|
iconPrefix | icon |
localIconPrefix | icon-local |
collectionName | 从 localIconPrefix 推导,默认 local |
localIconPath | src/assets/svg-icon |
scale | 1 |
覆盖图标目录和前缀:
import { fileURLToPath } from 'node:url';
import { defineConfig } from '@skyroc/web-admin-vite';
const localIconPath = fileURLToPath(new URL('./src/icons', import.meta.url));
export default defineConfig({
application: {
plugins: {
unocss: {
iconPrefix: 's-icon',
localIconPrefix: 's-icon-local',
localIconPath
},
unpluginIcon: {
iconPrefix: 's-icon',
localIconPrefix: 's-icon-local',
localIconPath
},
autoImport: {
iconPrefix: 's-icon',
localIconPrefix: 's-icon-local',
localIconPath
}
}
}
});如果只是普通 admin 应用,建议保持默认图标目录和前缀,避免三个插件重复配置。
默认自动导入:
reactFC typereact-i18nextahookssrc/components/**src/config.tsA 前缀组件,例如 AButton -> Button追加扫描目录:
export default defineConfig({
application: {
plugins: {
autoImport: {
dirs: ['src/components/**', 'src/hooks/**'],
dts: 'src/types/auto-imports.d.ts'
}
}
}
});关闭 Ant Design A 前缀解析:
export default defineConfig({
application: {
plugins: {
autoImport: {
antd: false
}
}
}
});默认 build 时向 index.html 的 <head> 注入构建时间:
<meta
name="buildTime"
content="2026-05-25 12:00:00"
/>修改 meta 名称:
export default defineConfig({
application: {
plugins: {
html: {
metaName: 'x-build-time'
}
}
}
});projectInfo 在 Vite 启动时向终端打印项目提示。
export default defineConfig({
application: {
plugins: {
projectInfo: {
message: 'Skyroc Admin',
colors: ['#646cff', 'magenta'],
boxenOptions: {
borderStyle: 'round',
padding: 0.5
}
}
}
}
});关闭:
export default defineConfig({
application: {
plugins: {
projectInfo: false
}
}
});关闭 inspect:
export default defineConfig({
application: {
plugins: {
inspect: false
}
}
});配置 remove-console:
export default defineConfig({
application: {
plugins: {
removeConsole: {
includes: ['log', 'warn']
}
}
}
});需要使用 Vite 原生能力时,放到 vite 字段。
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig({
application: {
css: {
additionalData: '@use "@/styles/scss/global.scss" as *;'
}
},
vite: {
optimizeDeps: {
include: ['antd']
},
resolve: {
conditions: ['source']
}
}
});vite 会在 admin 预设之后合并,因此它适合做最终覆盖。应用需要覆盖同一配置项时,优先评估是否已有 application 配置项;没有再用 vite。
绝大多数应用只用得到 defineConfig。下面这些底层 helper 也是公开的,供不想走整套预设、只想复用其中一段的场景使用。
| 符号 | 来源 | 作用 |
|---|---|---|
defineConfig | config.ts | 主入口,三种重载见配置入口 |
setupAdminVitePlugins | plugins/index.ts | 按固定顺序装配整组内置插件 |
createAdminBuildOptions | build.ts | 生成 build 段:产物命名与 manual chunks |
createAdminScssPreprocessorOptions | build.ts | 生成 SCSS additionalData 预处理配置 |
createAdminViteServiceConfig | proxy.ts | 从环境变量解析出主服务与其它服务的 baseURL |
createAdminViteProxy | proxy.ts | 由服务配置生成 dev server proxy |
createAdminViteProxyPattern | proxy.ts | 拼出代理匹配前缀 |
getBuildTime | time.ts | 生成注入 html 的 BUILD_TIME |
resolveAdminIconOptions | plugins/icon-utils.ts | 统一解析图标前缀、集合名与本地图标目录 |
八个插件工厂可以单独取用,参数类型即同名 SetupXxxOptions:
| 符号 | 产出 |
|---|---|
setupAdminRouterPlugins | TanStack Router 插件(返回数组) |
setupAdminReactPlugin | @vitejs/plugin-react |
setupAdminBabelPlugin | Jotai preset + React Compiler preset |
setupAdminUnocss | UnoCSS 及其 icon preset |
setupAdminUnpluginIcon | unplugin-icons + svg sprite(返回数组) |
setupAdminAutoImport | React / i18n / ahooks / antd / 图标自动导入 |
setupAdminHtmlPlugin | 往 html 注入 buildTime meta |
setupAdminProjectInfo | 启动时打印终端项目信息 |
类型侧还导出 AdminViteEnv、AdminViteUserConfig、AdminViteApplicationOptions、DefineAdminViteConfig、MaybePluginConfig 等,可用来给应用自己的配置工厂标注类型。
从应用本地 build/* 迁移到本包时,推荐顺序:
packages/web/admin-vite/srcapps/admin/vite.config.ts 改为直接 import { defineConfig } from '@skyroc/web-admin-vite'application.css.additionalDatabuild/config、build/plugins、build/shared 这类桥接代码predev、prebuild、prepreview 中先构建 @skyroc/web-admin-vite应用入口应尽量保持这种形态:
import { defineConfig } from '@skyroc/web-admin-vite';
export default defineConfig({
application: {
css: {
additionalData: '@use "@/styles/scss/global.scss" as *;'
}
}
});不是。图标前缀已经收口为插件 options:
plugins: {
unocss: { iconPrefix: 'icon', localIconPrefix: 'icon-local' },
unpluginIcon: { iconPrefix: 'icon', localIconPrefix: 'icon-local' },
autoImport: { iconPrefix: 'icon', localIconPrefix: 'icon-local' }
}默认值就是 icon / icon-local,普通应用无需配置。
共享 workspace 包在 Vite dev 模式下可能解析到不同 React 实例,触发 Invalid hook call。默认 dedupe 这些运行时入口:
['react', 'react-dom', 'react/jsx-dev-runtime', 'react/jsx-runtime'];除非确定所有依赖解析稳定,否则不要关闭 dedupeReact。
包的发布入口指向 dist/index.mjs。本地 workspace 直接消费时,Vite 运行时也会加载 dist。如果源码已变但 dist 未更新,应用会使用旧逻辑。
建议在应用脚本里加:
{
"scripts": {
"build:admin-vite": "pnpm --filter @skyroc/web-admin-vite build",
"predev": "pnpm run build:admin-vite",
"prebuild": "pnpm run build:admin-vite",
"prepreview": "pnpm run build:admin-vite"
}
}优先用 application,因为它表达的是 admin 应用语义,例如代理、构建、插件开关、别名、dev server。
只有这些情况再用 vite:
prependPlugins / appendPlugins修改本包后建议至少运行:
pnpm --filter @skyroc/web-admin-vite typecheck
pnpm --filter @skyroc/web-admin-vite build如果同时改了应用消费方式,再运行:
pnpm --filter skyroc-admin typecheckLast updated on