Vite 进阶配置:插件开发、按需加载与生产环境优化

目标与场景
- 插件开发:编写可复用的 Vite 插件(基于 Rollup 插件接口 + Vite 拓展钩子)
- 按需加载:路由/组件/资源的懒加载与自动导入,提高首屏与交互性能
- 生产优化:分包策略、预构建、资源提示与分析,稳定降低包体与构建时间
插件架构与钩子
- 基于 Rollup 插件体系,Vite 额外提供
configureServer、transformIndexHtml、handleHotUpdate - 插件编写要点:
name唯一、apply指定运行阶段('serve' | 'build' | 'client' | 'server')- 使用
enforce: 'pre' | 'post'控制钩子前后顺序
示例:注入构建 banner + 开发阶段虚拟模块
ts
// vite-plugin-banner.ts
import type { Plugin } from 'vite'
export default function bannerPlugin(text = 'Built with Vite'): Plugin {
return {
name: 'vite-plugin-banner',
apply: 'build',
generateBundle(_, bundle) {
for (const f of Object.values(bundle)) {
if (f.type === 'chunk') f.code = `/* ${text} */\n` + f.code
}
}
}
}
// vite-plugin-virtual.ts
import type { Plugin } from 'vite'
const ID = 'virtual:env'
export default function virtualEnvPlugin(): Plugin {
return {
name: 'vite-plugin-virtual-env',
resolveId(id) { return id === ID ? id : null },
load(id) { if (id === ID) return `export const mode = '${process.env.NODE_ENV}'` },
handleHotUpdate(ctx) {
if (ctx.file.includes('.env')) ctx.server.ws.send({ type: 'full-reload' })
}
}
}
示例:注入 HTML 资源提示
ts
// vite-plugin-preload.ts
import type { Plugin } from 'vite'
export function preloadPlugin(): Plugin {
return {
name: 'vite-plugin-preload',
transformIndexHtml(html) {
const hint = `<link rel="preconnect" href="https://cdn.example.com">`
return html.replace('</head>', `${hint}</head>`)
}
}
}
开发服务器拓展
- 通过
configureServer注入中间件,或调用server.ws.send实现自定义热更新
ts
// vite-plugin-middleware.ts
import type { Plugin } from 'vite'
export function middlewarePlugin(): Plugin {
return {
name: 'vite-plugin-middleware',
apply: 'serve',
configureServer(server) {
server.middlewares.use('/health', (_req, res) => { res.statusCode = 200; res.end('ok') })
}
}
}
按需加载策略
- 路由懒加载:
() => import('...')动态导入分离路由包
ts
// vue-router
const routes = [ { path: '/', component: () => import('@/pages/Home.vue') } ]
- 文件式路由与批量懒加载:
ts
const pages = import.meta.glob('/src/pages/**/*.vue', { eager: false })
- 组件按需与自动导入:
ts
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default { plugins: [
AutoImport({ imports: ['vue','vue-router','pinia'] }),
Components({ resolvers: [ElementPlusResolver()] })
] }
- 资源懒加载:图片
loading="lazy"、大型组件defineAsyncComponent、非关键脚本type=module+async/defer
生产环境优化配置
- 分包策略与手动切块:
ts
// vite.config.ts(Rollup 配置)
import { defineConfig } from 'vite'
export default defineConfig({
build: {
sourcemap: true,
chunkSizeWarningLimit: 800,
rollupOptions: {
output: {
manualChunks: {
framework: ['vue','vue-router','pinia'],
ui: ['element-plus'],
chart: ['echarts']
}
}
}
}
})
- 预构建与依赖优化:
ts
export default defineConfig({
optimizeDeps: { include: ['lodash-es','dayjs'], exclude: ['big-lib'] }
})
- 资源提示与公共路径:
ts
export default defineConfig({
base: 'https://cdn.example.com/',
build: { assetsInlineLimit: 8 * 1024 }
})
- CSS 与图片:开启 CSS 代码分割(默认),图片使用 AVIF/WebP 与响应式
srcset - Env 与编译:
define注入常量、esbuild目标(target: 'es2017')减少转译成本
SSR/SSG 与 Streaming(可选)
ssr.noExternal控制外部依赖打包;vite-plugin-ssr或框架内置(Nuxt/Next)实现 SSR/SSG- HTML Streaming:结合框架 Suspense 输出,提高可感知速度
构建分析与检查
- 可视化:
ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({ build: { rollupOptions: { plugins: [visualizer({ filename: 'stats.html' })] } } })
- 插件诊断:
vite-plugin-inspect查看插件链与转换结果
ts
import Inspect from 'vite-plugin-inspect'
export default defineConfig({ plugins: [Inspect()] })
Dev 与 Proxy
ts
export default defineConfig({
server: {
proxy: {
'/api': { target: 'https://api.example.com', changeOrigin: true, rewrite: p => p.replace(/^\/api/, '') }
}
}
})
生产脚本与 CI
- 使用
CI=true vite build --mode production固化生产模式;在 CI 缓存node_modules与.vite目录 - 结合
pnpm i --frozen-lockfile与构建日志采集,形成度量闭环
常见坑与修复
- 预构建冲突:
optimizeDeps.include/exclude精确控制;避免同时引入 CJS/ESM 导致重复 - 过度分包导致请求过多:为首屏路由保留合并,后续路由按需分割
- 插件顺序:
enforce配置不当导致转换顺序错误;通过vite-plugin-inspect排查 - CDN 路径与资源 404:
base与静态资源路径需一致;部署端正确配置缓存与回源
实战清单(12 项)
- 编写通用插件:banner、virtual、preload 与中间件注入
- 路由/文件式懒加载:
import()与import.meta.glob - 自动导入:
unplugin-auto-import与组件按需unplugin-vue-components - 分包:框架/UI/图表独立与首屏合并;
manualChunks - 预构建:
optimizeDeps的 include/exclude 管理 - CDN 与公共路径:
base、assetsInlineLimit - 图片与字体:现代格式与
font-display: swap - Env 与编译:
define与esbuild目标 - SSR/SSG(可选):
ssr.noExternal与 Streaming - 分析:visualizer 与 inspect
- DevServer 与代理:
server.proxy与中间件 - CI:锁定依赖、缓存目录与构建日志度量
结果与总结
- 通过插件与按需策略,首屏包体与交互性能显著改善;生产构建更稳定、分析与度量更清晰
- 建议以"度量→策略→验证"的闭环长期维护,结合 CDN 与缓存策略持续优化用户体验
高级插件示例
ts
import type { Plugin } from 'vite'
export function rewritePlugin(): Plugin {
return {
name: 'vite-plugin-rewrite',
enforce: 'pre',
transform(code, id) {
if (id.endsWith('.ts') || id.endsWith('.js')) return code.replace(/@\//g, '/src/')
}
}
}
预构建与扫描优化
ts
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
entries: ['src/main.ts'],
include: ['lodash-es','dayjs'],
esbuildOptions: { target: 'es2017' }
}
})
模块预加载
ts
export default defineConfig({ build: { modulePreload: { polyfill: true } } })
构建度量
bash
CI=true vite build --mode production --profile
文件系统与 HMR
ts
export default defineConfig({ server: { fs: { strict: true }, hmr: { overlay: true } } })
更多问题与定位
- 插件覆盖与顺序:调整
enforce并使用vite-plugin-inspect观察链路 - CJS 与 ESM 混用:通过
optimizeDeps.exclude排除并统一使用 ESM 入口 - 资源哈希与缓存:校验
build.assetsInlineLimit与输出哈希策略
度量目标
- 首屏路由包体下降 30% 以上
- 构建时间下降 40% 以上,二次构建下降 70% 以上
- 预构建扫描耗时下降 50% 以上