Vite 构建工具
从「手工作坊」到「智能工厂」—— 前端工程化的核心利器
01 构建工具是什么
你写的前端代码就像原材料(钢板、螺丝、电线),但用户浏览器需要的是成品(一辆车)。
没有构建工具 = 手工作坊:工人一个一个拧螺丝(手动管理 script 标签、手动压缩、手动兼容浏览器)→ 慢、易出错。
有了构建工具 = 自动化工厂:原材料上流水线 → 自动切割、焊接、质检、打包 → 成品出厂。
为什么不能直接写 HTML?
一个小项目当然可以直接写 HTML。但制造业仪表盘这样的项目通常涉及:
| 问题 | 具体表现 | 构建工具的解决方案 |
|---|---|---|
| 模块化 | 几十个 JS 文件,用 <script> 一个一个引入,顺序还不能错 | import/export 自动管理依赖 |
| 新语法兼容 | 用了 ES6+ 语法,IE/旧浏览器不认 | 自动转译成 ES5 |
| 代码压缩 | 上线时手动删除空格和注释 | 自动 minify,体积减小 60%+ |
| 样式处理 | Sass/Less 写完后要手动编译成 CSS | 自动预处理并注入 |
| 资源优化 | 图片没有压缩、没有缓存控制 | 自动 hash 命名、懒加载 |
构建工具做了什么?
Sass→CSS
合并/拆分
Minify
可直接部署
构建工具 = 把你写的「开发友好」的源代码,自动转换成「浏览器能高效运行」的生产代码。
02 Webpack vs Vite
Webpack = 老式工厂:接了 1000 个订单,要把所有零件全部组装完才能发货。启动慢(全量打包),但最终产物很可靠。
Vite = 现代工厂:客户要哪个零件,现场马上做哪个(按需编译)。启动极快(利用浏览器原生 ES Module),开发体验丝滑。
| 对比维度 | Webpack 老式工厂 | Vite 现代工厂 |
|---|---|---|
| 开发启动 | 慢(几十秒~几分钟) 全部文件打包完才能启动 | 极快(毫秒级) 不打包,按需编译 |
| 热更新 (HMR) | 改一行 → 重新打包整块 | 改一行 → 只替换那一个模块 |
| 底层引擎 | 自研打包器 | 开发:esbuild(Go语言,快10~100倍) 生产:Rollup |
| 配置复杂度 | 高(webpack.config.js 很长) | 低(开箱即用,极少配置) |
| 生态成熟度 | 非常成熟(10年历史) | 快速追赶(2020年发布,Vue/React 官方推荐) |
| 适用场景 | 老项目维护、复杂定制需求 | 新项目首选、所有现代前端项目 |
为什么 Vite 这么快?
Webpack 启动流程
1. 读取 webpack.config.js
2. 从 entry 出发,递归解析所有 import
3. 把所有模块打包成 bundle.js
4. 启动 dev server
→ 项目越大,启动越慢(线性增长)
Vite 启动流程
1. 启动 dev server(瞬间)
2. 浏览器请求首页 → 返回 index.html
3. 遇到 <script type="module"> → 按需编译
4. 只编译当前页面用到的文件
→ 不管项目多大,启动都很快
// Webpack: 启动时打包所有文件
Entry → ModuleA → ModuleB → ModuleC → ...
→ ModuleD → ModuleE → ...
→ ModuleF → ModuleG → ModuleH → ...
↓
bundle.js (3MB)
↓
启动 dev server ← 要等几十秒
// Vite: 浏览器请求什么,才编译什么
浏览器请求 index.html
→ 加载 main.js
→ import Dashboard.vue ← 只编译这一个文件
→ import api.js ← 只编译这一个文件
启动时间:~300ms ← 不管项目多大
Webpack = 每天开工前,先把所有原材料全部加工成半成品,再开始组装。准备时间长,但后续稳定。
Vite = 丰田精益生产(Just-In-Time)。需要什么零件,现生产什么。零库存、零等待。
03 Vite 项目搭建
3.1 创建项目
# 创建 Vite 项目(交互式选择框架)
$ npm create vite@latest my-dashboard
# 或者直接指定模板
$ npm create vite@latest my-dashboard -- --template vue
$ npm create vite@latest my-dashboard -- --template react
3.2 安装依赖 & 启动
$ cd my-dashboard
$ npm install
$ npm run dev
Webpack 项目启动通常要 10~60 秒。Vite 只要 不到 1 秒。
类比:老式工厂每天开机预热要 30 分钟,现代工厂按下开关就能干活。
3.3 项目结构
Webpack 入口是 JS 文件(entry: './src/main.js'),Vite 入口是 HTML 文件(index.html)。
这是因为 Vite 利用浏览器原生 ES Module,从 HTML 开始加载,按需引入 JS。
3.4 package.json 命令
{
"name": "my-dashboard",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite", // 开发服务器(热更新)
"build": "vite build", // 生产构建(输出到 dist/)
"preview": "vite preview" // 本地预览生产构建
}
}
04 配置文件 vite.config.js
默认配置就像标准化流程,开箱即用。但制造业项目通常需要定制:API代理(原料从哪进货)、路径别名(零件编号简写)、插件(加装特殊设备)。
4.1 制造业仪表盘的完整配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
// ① 插件 —— 扩展 Vite 能力
plugins: [
vue(), // 让 Vite 能解析 .vue 文件
],
// ② 开发服务器配置
server: {
port: 3000, // 改为 3000 端口(默认 5173)
open: true, // 启动时自动打开浏览器
// ③ API 代理 —— 解决跨域问题
proxy: {
// 前端请求 /api/machine/status
// → 自动转发到 http://localhost:8080/api/machine/status
'/api': {
target: 'http://localhost:8080', // 后端服务地址
changeOrigin: true, // 修改请求头中的 Origin
// rewrite: (path) => path.replace(/^\/api/, '')
// ↑ 如果后端接口没有 /api 前缀,取消注释
},
},
},
// ④ 路径别名 —— 简化 import 路径
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
// 使用前:import Dashboard from '../../../components/Dashboard.vue'
// 使用后:import Dashboard from '@/components/Dashboard.vue'
},
},
// ⑤ 生产构建优化
build: {
outDir: 'dist', // 输出目录
sourcemap: false, // 生产环境不生成 sourcemap
chunkSizeWarningLimit: 1000, // chunk 大小警告阈值(KB)
rollupOptions: {
output: {
// 分包策略 —— 按依赖拆分,利用浏览器缓存
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'echarts-vendor': ['echarts'],
},
},
},
},
})
4.2 API 代理详解
前端(车间 A)需要从后端(仓库 B)拿数据,但浏览器有跨域限制(不同部门不能直接对接)。
Vite 代理 = 中间设一个「采购代办处」,前端请求发给代办处(同域),代办处再去后端取数据。
// 开发环境中,请求会经过 Vite 代理
// 前端发起:
fetch('/api/machine/status')
// 实际请求 → http://localhost:8080/api/machine/status
// 另一个例子:获取 OEE 数据
fetch('/api/oee/realtime?line=L1')
// 实际请求 → http://localhost:8080/api/oee/realtime?line=L1
代理只在开发环境(npm run dev)有效。生产环境需要 Nginx 等反向代理来处理。
4.3 路径别名效果
// ❌ 没有别名 —— 相对路径地狱
import Dashboard from '../../../components/Dashboard.vue'
import { getOEE } from '../../api/oee'
import formatTime from '../../utils/format'
// ✅ 有别名 @ → src/
import Dashboard from '@/components/Dashboard.vue'
import { getOEE } from '@/api/oee'
import formatTime from '@/utils/format'
05 开发 vs 生产
npm run dev = 草稿模式:设计师在画草图,可以随时擦掉重画,有辅助线(source map),速度优先。
npm run build = 定稿发布:把草图变成印刷品。去掉辅助线(minify),只保留必要内容(tree shaking),加上防伪标记(hash)。
| 特性 | dev 草稿模式 | build 定稿发布 |
|---|---|---|
| 代码压缩 | ❌ 不压缩(方便调试) | ✅ 压缩(变量名缩短、删除空格) |
| Source Map | ✅ 有(浏览器能看到源码) | ❌ 没有(保护源码) |
| Tree Shaking | 不需要 | ✅ 删除未使用的代码 |
| 文件 Hash | 不需要 | ✅ app.3a7b2c.js(缓存控制) |
| 热更新 (HMR) | ✅ 改代码立即生效 | ❌ 不适用 |
| API 代理 | ✅ vite.config.js 中的 proxy | ❌ 需要 Nginx 配置 |
| 用途 | 本地开发调试 | 部署到服务器给用户访问 |
5.1 npm run dev — 开发模式
$ npm run dev
修改 src/components/Dashboard.vue 中的文字:
+ <h1>产线实时监控</h1>
保存文件后,浏览器自动更新,不需要刷新页面!保留了页面状态(如已选中的标签页、表单输入等)。
5.2 npm run build — 生产构建
$ npm run build
vue-vendor-Di43x2aC.js — Vue 框架代码。文件名中的 Di43x2aC 是内容哈希:代码没变,哈希不变(浏览器缓存有效);代码变了,哈希变了(用户拿到最新版)。
gzip: 98.17 kB — 实际传输大小。ECharts 从 341KB 压缩到 98KB,节省 71%。
5.3 Tree Shaking 详解
// utils.js — 导出了 3 个函数
export function formatTime(t) { /* ... */ }
export function parseData(d) { /* ... */ }
export function generateReport(r) { /* ... 500行 ... */ }
// Dashboard.vue — 只用了 2 个
import { formatTime, parseData } from '@/utils'
// 生产构建时:
// generateReport 被自动删除(摇掉了)
// 结果:打包体积减小,加载速度更快
06 与 Vue/React 配合
Vite 对 Vue 和 React 都有一等支持。创建项目时选择对应模板即可。
6.1 Vue 3 项目
# 方式一:交互式选择 Vue
$ npm create vite@latest factory-dashboard -- --template vue
# 方式二:使用 Vue 官方脚手架(内含更多预设)
$ npm create vue@latest factory-dashboard
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
})
<template>
<div class="dashboard">
<h1>产线实时监控</h1>
<OEEChart :line-id="'L1'" />
<MachineStatus />
</div>
</template>
<script setup>
import OEEChart from '@/components/OEEChart.vue'
import MachineStatus from '@/components/MachineStatus.vue'
</script>
6.2 React 项目
# 使用 JavaScript 模板
$ npm create vite@latest factory-dashboard -- --template react
# 使用 TypeScript 模板
$ npm create vite@latest factory-dashboard -- --template react-ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
import { useState } from 'react'
import OEEChart from '@/components/OEEChart'
import MachineStatus from '@/components/MachineStatus'
function App() {
const [lineId, setLineId] = useState('L1')
return (
<div className="dashboard">
<h1>产线实时监控</h1>
<OEEChart lineId={lineId} />
<MachineStatus />
</div>
)
}
export default App
| 框架 | 模板名 | 插件 | 官方脚手架 |
|---|---|---|---|
| Vue 3 | --template vue | @vitejs/plugin-vue | npm create vue@latest |
| React | --template react | @vitejs/plugin-react | Vite 默认即可 |
| Vue 3 + TS | --template vue-ts | 同上 + TypeScript | npm create vue@latest |
| React + TS | --template react-ts | 同上 + TypeScript | Vite 默认即可 |
07 常用插件
基础工厂(Vite)能做基本加工,但你可以加装设备:自动包装机(压缩)、质量检测仪(代码分析)、特殊焊接器(Vue/React 解析)。
| 插件 | 作用 | 使用场景 |
|---|---|---|
@vitejs/plugin-vue |
让 Vite 能解析 .vue 单文件组件 |
Vue 3 项目必装 |
@vitejs/plugin-react |
让 Vite 支持 React JSX 语法 | React 项目必装 |
vite-plugin-compression |
构建时生成 .gz 压缩文件 |
生产部署优化,Nginx 可直接提供 gzip |
rollup-plugin-visualizer |
生成打包体积可视化分析图 | 优化包体积,发现大依赖 |
vite-plugin-svg-icons |
SVG 雪碧图,图标按需加载 | 制造业项目大量设备图标 |
@vitejs/plugin-legacy |
为旧浏览器生成兼容代码 | 需要支持 IE 或内网旧浏览器 |
7.1 完整插件配置示例
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import compression from 'vite-plugin-compression'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
// ① Vue 支持
vue(),
// ② Gzip 压缩
compression({
algorithm: 'gzip',
threshold: 10240, // 大于 10KB 的文件才压缩
}),
// ③ 打包分析(构建后生成 stats.html)
visualizer({
open: true, // 构建完自动打开分析页面
filename: 'stats.html',
}),
],
})
$ npm install -D vite-plugin-compression rollup-plugin-visualizer
7.2 打包分析效果
构建完成后会自动打开 stats.html,以矩形树图形式展示每个依赖的体积占比:
341 KB (62%)
52 KB (9%)
18 KB
12 KB
28 KB
一眼看出 ECharts 占了大头 → 可以考虑按需引入来优化。
08 面试高频考点
以下 6 道题覆盖了 Vite/Webpack 面试中最常问的知识点。
核心原因:开发阶段不打包。
1. 利用浏览器原生 ES Module:Vite 启动时不打包所有文件,而是启动一个 dev server。浏览器通过 <script type="module"> 直接请求所需的模块,Vite 按需编译后返回。
2. 使用 esbuild 预构建:依赖(node_modules)使用 Go 语言编写的 esbuild 进行预构建,比 Webpack 的 JavaScript 打包快 10~100 倍。
3. 强缓存策略:依赖预构建结果会被缓存(node_modules/.vite/),不变就不重新构建。源码部分的请求通过 304 协商缓存。
对比 Webpack:Webpack 启动时需要从 entry 递归解析所有模块的依赖关系,全部打包成 bundle 后才能启动服务。项目越大,启动越慢。
HMR = 修改代码后,只替换变化的模块,不刷新整个页面。
工作流程:
1. 文件变化:你保存了 Dashboard.vue
2. WebSocket 通知:Vite dev server 通过 WebSocket 告诉浏览器「Dashboard.vue 变了」
3. 请求新模块:浏览器只重新请求这一个文件的最新版本(带时间戳缓存失效)
4. 替换执行:框架(Vue/React)的 HMR runtime 接收新模块,替换旧的,保持页面状态不变
为什么比 Webpack 快:Webpack HMR 需要重新打包受影响的 chunk;Vite 只需要重新编译那一个文件,不需要重新计算依赖图。
// WebSocket 通信
Server → Client: { "type": "update", "path": "/src/components/Dashboard.vue" }
// 浏览器收到后
import('/src/components/Dashboard.vue?t=1718012345') // 带时间戳,绕过缓存
.then(newModule => {
// Vue HMR runtime 自动替换组件
hot.accept(newModule)
})
Tree Shaking = 摇掉没用到的代码,减小打包体积。
前提条件:使用 ES Module(import/export),不能用 CommonJS(require/module.exports)。因为 ES Module 是静态的,打包工具可以在编译时分析出哪些导出没被使用。
工作原理:
1. Rollup(Vite 的生产打包引擎)从入口文件开始,分析所有 import 语句
2. 构建「模块依赖图」
3. 标记所有被使用的 export
4. 删除未被标记的代码(Dead Code Elimination)
// 📦 utils.js
export function used() { return '我被用到了' } // ✅ 保留
export function unused() { return '没被用到' } // ❌ 删除
// 📄 main.js
import { used } from './utils' // 只导入了 used
console.log(used()) // unused 不会被包含在产物中
Code Splitting = 把一个大包拆成多个小包,按需加载。
类比:不把整本百科全书一次性搬过来,而是需要查「ECharts」时再去拿那一册。
方式一:动态 import(推荐)
// 路由懒加载 —— 只有点击菜单时才加载对应页面
const routes = [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue') // 懒加载
},
{
path: '/report',
component: () => import('@/views/Report.vue') // 懒加载
}
]
方式二:manualChunks(vite.config.js)
// vite.config.js — 手动分包
build: {
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router'],
'echarts': ['echarts'],
}
}
}
}
好处:首屏只加载核心代码(Vue + 首页),ECharts 等大库按需加载。首屏加载从 500KB 降到 100KB。
| 配置项 | 用途 | 示例 |
|---|---|---|
server.port | 开发服务器端口 | port: 3000 |
server.proxy | API 代理(解决跨域) | proxy: { '/api': { target: '...' } } |
server.open | 启动时自动打开浏览器 | open: true |
resolve.alias | 路径别名 | '@': path.resolve(__dirname, 'src') |
build.outDir | 构建输出目录 | outDir: 'dist' |
build.sourcemap | 是否生成 sourcemap | sourcemap: true |
build.rollupOptions | Rollup 构建选项(分包等) | manualChunks: { ... } |
plugins | 插件列表 | [vue()] |
base | 公共基础路径 | base: '/dashboard/' |
css.preprocessorOptions | CSS 预处理配置 | scss: { additionalData: '...' } |
虽然 Vite 越来越流行,但 Webpack 仍然是面试高频考点,很多老项目也在用。5 个核心概念:
| 概念 | 作用 | 类比 | 示例 |
|---|---|---|---|
| Entry 入口 |
打包的起点,Webpack 从这里开始分析依赖 | 工厂的起始工位 | entry: './src/main.js' |
| Output 输出 |
打包后的文件存放到哪里,叫什么名字 | 成品仓库地址 | output: { path: 'dist/', filename: 'bundle.[hash].js' } |
| Loader 加载器 |
让 Webpack 能处理非 JS 文件(CSS、图片、Vue 等) | 特殊加工设备 | module: { rules: [{ test: /\.vue$/, loader: 'vue-loader' }] } |
| Plugin 插件 |
扩展 Webpack 功能(压缩、生成 HTML、环境变量) | 工厂附加设备 | plugins: [new HtmlWebpackPlugin()] |
| Mode 模式 |
development 或 production,自动启用对应优化 | 草稿模式 / 定稿模式 | mode: 'production' |
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development', // 模式
entry: './src/main.js', // 入口
output: { // 输出
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[contenthash:8].js',
},
module: { // Loader
rules: [
{ test: /\.vue$/, loader: 'vue-loader' },
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
],
},
plugins: [ // Plugin
new HtmlWebpackPlugin({ template: './index.html' }),
],
}
当面试官问 Webpack 时,你可以主动提到:「Webpack 的概念我也熟悉,不过新项目我会优先选 Vite,因为它解决了 Webpack 最大的痛点——开发启动慢的问题。」
中际旭创 · 制造业全栈工程师培训 · 第 11 课
Vite 构建工具 — 让前端开发从「手工作坊」升级为「智能工厂」