前端构建工具:Webpack不够用了之后
但这次把一个跑了三年的 Webpack 项目换成 Vite,不是因为 Vite 新,也不是因为大家都说它快,纯粹是因为每次 都要等上 5 分钟,而每次改完代码后刷新浏览器也要等上十几秒。
项目不算大,大约 20 个页面,Vue 2 + TypeScript,用了 Webpack 4 配置。
为什么动手
项目不算大,大约 20 个页面,Vue 2 + TypeScript,用了 Webpack 4 配置。最开始的时候项目还小,构建慢也能忍。但随着业务堆上去,问题就慢慢暴露了:
- 本地开发改一行代码,HMR 要等 8-15 秒
- 打包命令跑完要 5 分钟,CI/CD 流水线经常超时
- Webpack 配置文件堆到了 800 行,每次改点东西都要小心翼翼
- 新人入职光是理解构建配置就要花半天
不是没想过优化,试过多进程、cache-loader、硬 source-map,效果有但有限。Webpcak 4 本身的限制就在那儿,再怎么调也跳不出它的框。
决定换 Vite 的那一刻,更多是无奈:要么继续忍受,要么赌一把迁移成本。
迁移前的准备
换工具不是拍脑袋就干,先做技术调研。主要确认了几件事:
- 项目里有没有 Webpack 特有的 loader 和 plugin
- 第三方库有没有 ESM 版本或者兼容性问题
- 团队成员是否接受新工具的学习成本
- CI/CD 环境是否需要调整
翻了一遍 package.json 和 webpack.config.js,发现用到的 loader 主要是:
vue-loader处理.vue文件ts-loader处理 TypeScriptfile-loader处理静态资源css-loader和style-loader处理样式
plugin 相对简单,主要是 HtmlWebpackPlugin 和 CopyWebpackPlugin。看起来都能在 Vite 生态里找到对应方案。
第三方库这块稍微麻烦,有些老旧依赖还是 CommonJS 格式。但 Vite 底层用了 Rollup,天生支持 CJS 转 ESM,问题不大。
唯一纠结的是团队学习成本。但想想每天 wasted 在等构建上的时间,还是值得。
第一步:安装和基础配置
先装依赖:
npm install vite @vitejs/plugin-vue2 --save-dev
npm remove webpack webpack-cli webpack-dev-server
建一个新的 vite.config.ts:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue2'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'vuex'],
'utils': ['lodash-es', 'axios']
}
}
}
}
})
改一下 package.json 里的 scripts:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
跑一下 npm run dev,本想着能直接起飞,结果直接报错。
踩坑与解决
坑一:入口文件找不到
Webpack 项目通常入口是 src/main.js,但 Vite 默认找 index.html。改了半天才发现,Vite 的 HTML 要手动引入脚本:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>My App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
之前 Webpack 用 HtmlWebpackPlugin 自动注入,现在要手动写。虽然麻烦一点,但透明度更高。
坑二:环境变量不兼容
Webpack 项目用了 process.env.NODE_ENV,但在 Vite 里取不到。Vite 用的是 import.meta.env,而且要显式声明才能用:
// vite.config.ts
export default defineConfig({
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
})
或者统一改代码,把 process.env 换成 import.meta.env。最后选了后者,毕竟 Vite 的方式更标准。
坑三:动态 import 路径问题
项目里有这样的代码:
const module = require(`./modules/${moduleName}.js`)
Webpack 能处理这种动态路径,但 Vite 会直接报错。改成显式的 import:
const modules = import.meta.glob('./modules/*.js')
const module = await modules[`./modules/${moduleName}.js`]()
这算是 Vite 的一个限制,但换个角度想,显式总比隐式好。
坑四:样式文件处理
Webpack 项目里用了 @import 引入全局样式,但在 Vite 里有些路径解析不对。最后在 vite.config.ts 里加了 css.preprocessorOptions.scss.additionalData:
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
})
坑五:老旧依赖的 ESM 兼容
有个第三方库还是纯 CommonJS,动态 import 时出错。用了 Vite 的 optimizeDeps 配置:
export default defineConfig({
optimizeDeps: {
include: ['old-commonjs-lib']
}
})
这样 Vite 会在启动时预构建这些依赖,转成 ESM 格式。
构建优化
开发环境跑起来后,生产构建又遇到问题。初始打包体积比 Webpack 时大了 30%,主要是没有做代码分割。
调整了 rollupOptions.output.manualChunks,把 Vue 核心库和第三方工具包分开:
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('vue')) {
return 'vue-vendor'
}
if (id.includes('axios') || id.includes('lodash')) {
return 'utils'
}
return 'vendor'
}
}
}
}
同时启用了 build.chunkSizeWarningLimit 和 build.cssCodeSplit,把 CSS 也按 chunk 分开。
最终构建产物和 Webpack 版本相当,但构建时间从 5 分钟降到了 30 秒,压缩率还提高了 5%。
开发体验对比
迁移完成后,团队反馈最明显的是 HMR 速度。之前改个组件要等 8-15 秒,现在是 100-300ms,几乎感觉不到延迟。
Vite 的另一个优势是原生 ESM 支持。Webpack 在开发环境会把所有模块打包成 bundle,而 Vite 直接用浏览器的原生 ESM 加载,按需编译。这意味着修改的模块才会重新编译,而不是整个项目都跑一遍。
还有一个细节是错误提示。Vite 的错误信息更清晰,直接定位到源码位置,不像 Webpack 有时要猜。
遗留问题
不是所有问题都完美解决了。比如:
- SSR 渲染还没完全适配,生产环境暂时还是用 Webpack
- 有些 Webpack 特有的 plugin 还没找到等价方案,绕过去了
- CI/CD 环境需要调整 Node 版本和缓存策略
这些问题不算致命,但说明迁移不是一劳永逸的。
技术选型的一点思考
这次迁移让我重新思考了技术选型的问题。工具本身没有绝对的好坏,关键看场景。
Webpcak 成熟稳定,生态完善,适合大型复杂项目。Vite 新颖快速,开发体验好,适合中小项目和新项目。
但技术选型不能只看当下,还要考虑未来。Vite 背后的 Rollup 生态在成长,Vue 官方也在推,长远来看可能更值得投资。
迁移不是目的,解决问题才是。如果 Webpack 能满足需求,没必要硬换。但当你每天被构建速度折磨,而且有明确的优化路径时,就该动手了。
这次折腾花了一个月,中间想过放弃,但现在回头看,值。
毕竟,省下来的时间,可以用来做更有意思的事情。
版权声明: 本文首发于 指尖魔法屋-前端构建工具:Webpack不够用了之后(https://blog.thinkmoon.cn/post/109-frontend-build-tools-webpack-vite-evolution/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。