Vite
Proxy
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
})如果请求是/api开头的,就会被代理到http://localhost:8080
如果后端接口没有/api,那么就涉及到rewrite
{
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
}比如你发起/api/user/list,那么就会被代理到http://localhost:8080/user/list
也可以配置多个后端
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
},
'/ai': {
target: 'http://localhost:8000',
changeOrigin: true
}
}
}这个代理只在开发环境生效
alias
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': '/src',
},
},
})host
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0',
},
})配置之后,局域网也可以访问
.env
比如axios请求的baseURL
VITE_API_BASE_URL=/apiVite暴露给前端的环境变量必须以
VITE_开头
- 开发:
npm run dev,会自动加载.env.development - 生产:
npm run build,会自动加载.env.production
开发环境:基于原生 ESM
Webpack 在开发时需要抓取整个应用的依赖图并进行打包,而 Vite 跳过了此步骤。
- 利用原生 ESM:现代浏览器支持
import和export语法。Vite启动时,只启动一个简单的 HTTP 服务器,不进行打包。 - 按需请求:当你打开页面时,浏览器请求哪个文件,
Vite就会实时转换并返回哪个文件。- 例如:你请求
App.vue,Vite会在后台调用Vue编译器把它转换为JS,然后丢给浏览器。
- 例如:你请求
- 依赖预构建:为了解决
CommonJS兼容性和上百个小文件请求过慢的问题,Vite会在初始启动时使用esbuild将node_modules中的第三方库(如React、lodash)预先打包成一个大的ESM包。
💡 提示
esbuild是使用Go语言编写的,速度比传统JS编写的打包工具快很多。
生产环境:基于 Rollup
虽然开发环境不打包,但是为了生产环境的性能(减少 HTTP 请求、代码压缩、Tree Shaking),Vite 在执行 vite build 时依然会进行打包。
- 核心引擎:
Vite在生产环境使用Rollup进行打包。 - 为什么用
Rollup:Rollup在处理ESM模块、Tree Shaking和生成小体积包方面非常成熟且高效。 - 插件兼容:
Vite设计了一套兼容Rollup的插件接口,这意味着很多Rollup的插件可以直接在Vite中使用。
热更新(HMR)的底层差异
Webpack 和 Vite 在热更新(HMR)的底层实现上存在显著差异:
- Webpack:当你修改一个文件时,
Webpack需要重新计算依赖图。即使有缓存,随着项目增大,速度也会变慢。 - Vite:由于基于原生
ESM,Vite只需要让浏览器重新请求那个改变的文件即可。无论项目多大,热更新速度几乎是恒定延迟
为什么预构建要用 esbuild
- 编译语言优势:传统的打包工具如
Webpack、Rollup都是用JavaScript编写的。JS作为解释性语言,存在垃圾回收和JIT编译的开销。而esbuild是用Go语言编写的,直接编译成机器码,能够充分利用多核CPU的并行能力。 - 性能优势:在处理大型依赖库时,
esbuild的速度通常是Webpack或Rollup的 10 到 100 倍。
依赖预构建的目的
- CommonJS 转 ESM: 很多旧的
npm包依然是CommonJS规范的,而浏览器不支持CommonJS规范,因此需要将CommonJS规范的代码转换为ESM规范的代码。 - 减少网络请求(Bundle 瘦身): 有些库内部由几百个小文件组成,如果直接请求,会触发几百个
HTTP请求,导致网页加载较慢。esbuild会把这些小文件打包成一个大文件,显著减少HTTP请求次数。
为什么生产环境不用 esbuild
生产环境并不在乎打包花多少时间,而是更在乎最终生成的代码体积有多小。
- Rollup:它是
Tree Shaking的鼻祖,能够精准地分析哪些是没用的代码。在CSS拆分、代码分割和公共提取方面非常成熟。 - esbuild:虽然也有这些功能,但相对来说还不够成熟,生成的代码质量和体积不如
Rollup优化得极致。
Rollup 拥有一个庞大且稳定的插件生态系统,而 esbuild 还在完善中。对于很多复杂的构建场景,Rollup 的插件系统能够灵活地满足需求。
基础使用与原理
parcel 对比 零配置 vite 倾向于零配置
入口
vite 第一性,默许开发者是开发 web 应用,所以将index.html中的type="module" src="xxx的文件作为入口
模块解析
vite 在开发环境使用的是esbuild 进行构建,所以很多编译工作esbuild(go)都是原生支持的,比如:
- 支持 jsx
- 支持 typescript
- 支持 css 预处理器
- 支持 图片、字体等静态资源
按照需要去进行编译,并且会将编译结果缓存
另外一些配置
针对功能增强,plugin配置
模块解析,resolve配置
本地开发构建服务,server配置
样式额外处理, css配置
一些 vite 环境变量 define 配置
- 一般使用
.env文件来管理环境变量 注意:但是命名必须以VITE\_开头才能作为公共变量使用
- 一般使用
产物构建,build,esbuild 来配置
vite 插件
vite 插件和 webpack 插件差别很大,webpack中plugin一般是用来强化构建过程,通过暴露的插件时机钩子在不同时机做一些处理,要和loader区分开,loader的工作是模块编译与解析
基础使用
vite 插件是一个对象,对象中包含了一些钩子函数,这些钩子函数会在不同的时机被调用,插件的工作就是在这些时机做一些处理
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})vite 原理
- 借助浏览器的module支持
- 需要编译的内容需要做额外的编译
- css
- ts
- 两端
- 开发阶段,本地通过开打服务实现
- rollup打包进行处理
手动分包(Manual Chunk)
vite 生产构建使用 rollup,所以“分包”本质上是 rollup 的 chunk 策略。
常见做法有两类:
- 动态导入:用
import()触发按需加载(最推荐、最符合路由/功能模块拆分) - manualChunks:在构建配置里手动指定哪些模块要打到同一个 chunk(更偏工程优化)
1)动态导入分包
const { heavy } = await import('./heavy-module')常见应用:路由懒加载、低频功能(编辑器/图表/富文本)按需加载。
2)build.rollupOptions.output.manualChunks
在 vite.config 里配置:
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('/react/') || id.includes('/react-dom/'))
return 'react'
if (id.includes('/lodash-es/')) return 'lodash'
return 'vendor'
}
},
},
},
},
})分包策略速记
- 优先业务维度:按路由/功能模块分(动态导入),让首屏更轻、低频更晚加载
- 再做大依赖隔离:把更新不频繁、体积大的库单独 chunk(例如图表、编辑器、UI 库)
- vendor 不要太碎:拆得过细会增加请求数和调度开销,HTTP/2 下也不是越碎越好
常见坑
- 共享依赖重复:拆包不当会让某些依赖在多个 chunk 里重复,导致总体体积变大
- 缓存失效:随便把业务和 vendor 混在一起,会导致业务改动引起 vendor chunk hash 改变
- 只在 build 生效:manualChunks 主要影响生产构建,开发态模块加载机制不同
Auto Import
unplugin-vue-components
自动按需导入vue组件(包括UI库和你自己的组件),无需手动import和components注册
安装
npm install unplugin-vue-components -D配置
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
Components({
// 自动扫描 src/components 下的组件(默认已包括)
dirs: ['src/components'],
// 扩展名(默认 .vue)
extensions: ['vue'],
// 生成类型声明文件(TS 支持)
dts: 'src/typings/components.d.ts',
// 解析器:支持按需导入 Element Plus、Antd、Vant 等
resolvers: [
ElementPlusResolver(), // Element Plus 按需加载
// 也可以自定义: (name) => ({ name, from: `@/components/${name}` })
],
// 深度扫描(包括子目录)
deep: true,
}),
],
})类型支持
dst选项会生成components.d.ts文件,配合TS获得完整的类型提示
unplugin-auto-import
自动导入vue\vue-router\pinia等API(如ref、computed、useRouter),无需手动import
安装
npm install unplugin-auto-import -D配置
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
// 预设:自动导入哪些库的 API
imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'],
// 生成类型声明文件
dts: 'src/typings/auto-imports.d.ts',
// 解析器(与 Components 配合)
resolvers: [ElementPlusResolver()],
// 自动导入文件夹下的模块(可选)
dirs: ['src/composables/**', 'src/stores/**'],
// 是否在 ESLint 中忽略自动导入(避免 ESLint 报错“未定义”)
eslintrc: {
enabled: true, // 生成 .eslintrc-auto-import.json
filepath: './.eslintrc-auto-import.json',
globalsPropValue: true,
},
}),
],
})通常两者配合使用