升级概览
本次升级是将一个基于 Vue 2.5.16 + Webpack 4 的项目升级到 Vue 2.7.16 + Webpack 5,主要涉及:
- 核心依赖升级
- Webpack 配置变更
- 升级后问题修复
升级收益
- ✅ 升级到 Vue 2.7.16(Vue2 最后一个版本,支持 Composition API,为后续可能的升级 Vue3 打下基础 ,迁移至 Vue 2.7 - Vue.js 文档 )
- ✅ 升级到 Webpack 5(更好的性能和缓存,启动文件缓存,热启动开发服务器只需从原先的 14s 提升到 1.3s, 本地打包构建少量的增量更新命中缓存编译只需要 2s,构建完成只需要不到 8s)
核心依赖升级
1.1 主要版本升级
json
// Vue 相关
"vue": "^2.5.16" → "^2.7.16"
"vue-server-renderer": "^2.5.16" → "^2.7.16"
"vue-loader": "^14.2.2" → "^15.11.1"
"vue-template-compiler": "^2.5.16" → "^2.7.16"
// Webpack 核心
"webpack": "^4.44.1" → "^5.88.0"
"webpack-cli": "^3.2.0" → "^4.10.0"
"webpack-dev-server": "^3.11.0" → "^4.15.0"
"webpack-merge": "^4.2.1" → "^5.9.0"
1.2 新增依赖(webpack5 polyfills)
webpack5 不再自动提供 Node.js polyfills,需要手动安装。
json
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.1",
"path-browserify": "^1.0.1",
"stream-browserify": "^3.0.0",
"util": "^0.12.5",
"postcss": "^8.5.6",
"postcss-loader": "^6.2.1",
1.3 移除的依赖(webpack5 内置替代)
json
// 移除:不再需要的loader
"file-loader": "^3.0.1", // 用Asset Modules替代
"url-loader": "^1.1.2", // 用Asset Modules替代
Webpack Base Config 核心变更
2.1 移除 HappyPack,使用 webpack5 内置多线程
diff
// 移除 webpack4 的 HappyPack 配置
- const HappyPack = require('happypack');
- const os = require('os');
- const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
2.2 添加 webpack5 缓存配置
javascript
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
},
cacheDirectory: path.resolve(__dirname, '../node_modules/.cache/webpack'),
version: '1.0.0'
}
开启持久化缓存 (filesystem cache), 会在 node_modules/.cache/webpack 目录下生成缓存文件, 每次构建会优先使用缓存, 提升构建速度。
bash
client/node_modules/.cache/webpack/
├── default-development/ # 开发环境缓存 (297M)
└── default-production/ # 生产环境缓存 (298M)
缓存重置触发条件:
- 配置文件变更(webpack.config.js)
- 依赖包更新(package.json)
- 缓存版本升级(cache.version)
- Node.js 版本变更
2.3 Asset Modules 替代传统 loader
javascript
// 旧配置(url-loader)
{
test: /\.(png|jpg|gif|svg|ico)$/,
use: [{
loader: "url-loader",
options: {
limit: 1000,
name: "images/[name].[ext]"
}
}]
}
// 新配置(Asset Modules)
{
test: /\.(png|jpg|gif|svg|ico)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1000
}
},
generator: {
filename: 'images/[name].[ext]'
}
}
2.4 添加 Node.js polyfills
javascript
// webpack5 不再自动提供 Node.js polyfills,需要手动安装。
resolve: {
fallback: {
"timers": false,
"fs": false,
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"buffer": require.resolve("buffer"),
"util": require.resolve("util")
}
}
2.5 webpack5 优化配置
javascript
// 实验性功能
experiments: {
topLevelAwait: true
},
// 快照优化
snapshot: {
module: { timestamp: true },
resolve: { timestamp: true }
},
// 构建输出优化
stats: {
children: false,
chunks: false,
modules: false,
builtAt: false,
timings: true,
version: false
}
Webpack Client Config 变更
3.1 webpack-merge 导入方式变更
diff
// 旧方式
- const merge = require('webpack-merge');
// 新方式
+ const { merge } = require('webpack-merge');
3.2 参数解析方式变更
在升级到 Webpack 5 + webpack-cli 4 后,原有的自定义参数传递方式失效:
bash
# 报错:Unknown option '--swm=beta'
npm run build --swm=beta
# 原本期望的效果:通过--swm参数控制不同环境的构建
Webpack-cli 从 v3 升级到 v4 后,参数解析机制发生变化:
webpack-cli 版本 | 自定义参数支持 | 解析方式 |
---|---|---|
v3.x | ✅ 支持 | --custom-arg=value → yargs.argv.customArg |
v4.x | ❌ 不支持 | 只支持预定义的 webpack 选项 |
diff
// 旧方式
- const { swm = 'xxx', analysis = false, dll = false } = require('yargs').argv;
// 新方式
+ const swm = process.env.SWM || 'xxx';
+ const analysis = process.argv.includes('--analysis') || false;
+ const dll = process.argv.includes('--dll') || false;
更新 package.json 脚本, 新增环境特定的构建脚本:
diff
{
"scripts": {
// 原有脚本保持不变
"build": "cross-env NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",
// 新增环境特定的构建脚本
+ "build:beta": "cross-env SWM=beta NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",
+ "build:test": "cross-env SWM=test NODE_ENV=production webpack --config ./client/build/webpack.client.config.js --progress",
// 修复原有的环境脚本
- "upipe": "npm run build --swm app-dev"
+ "upipe": "cross-env SWM=app-dev npm run build"
}
}
3.3 DevServer 配置升级
javascript
// 旧配置
devServer: {
contentBase: path.resolve(__dirname, "../dist"),
disableHostCheck: true
}
// 新配置
devServer: {
static: {
directory: path.resolve(__dirname, "../dist")
},
allowedHosts: "all",
client: {
overlay: {
errors: false,
warnings: false
}
}
}
3.4 SplitChunks 策略优化
javascript
// 生产环境 vs 开发环境差异化配置
splitChunks: isProduction
? {
// 生产环境:复杂分包策略
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
vue: {
/* Vue相关库 */
},
ui: {
/* UI库 */
},
utils: {
/* 工具库 */
},
vendors: {
/* 其他第三方库 */
},
},
}
: {
// 开发环境:简单分包策略(避免热更新冲突)
chunks: 'async',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'initial',
priority: 10,
},
},
};
3.5 移除手动 TerserPlugin 配置
diff
// 移除手动配置,使用 webpack5 内置
- minimize: process.env.NODE_ENV !== "development",
- minimizer: [new TerserPlugin({ parallel: 4 })]
// 改为
+ minimize: isProduction; // webpack5 自动多线程压缩
PostCSS 配置迁移问题与解决
4.1 PostCSS 配置变更
javascript
// 旧方式:在 vue-loader 中配置
{
loader: "vue-loader",
options: {
postcss: [
autoprefixer({
browsers: ["> 1%", "ie >= 9", "iOS >= 6", "Android >= 2.1"]
}),
px2rem({ remUnit: 75 })
]
}
}
// 新方式:独立的 postcss-loader
{
test: /\.(css|less)$/,
use: [
"style-loader",
"css-loader",
"postcss-loader", // 新增
"less-loader"
]
}
4.2 创建独立的 postcss.config.js
javascript
// postcss.config.js
const autoprefixer = require('autoprefixer');
const px2rem = require('postcss-px2rem');
module.exports = {
plugins: [
autoprefixer({
overrideBrowserslist: ['> 1%', 'ie >= 9', 'iOS >= 6', 'Android >= 2.1'],
flexbox: 'no-2009', // 保留老式flexbox语法
remove: false, // 不移除过时的前缀
}),
px2rem({ remUnit: 75 }),
],
};
4.3 样式坑:Autoprefixer 移除浏览器前缀
升级后发现部分样式异常,对比线上版本发现 -webkit-box-orient: vertical
等浏览器前缀样式被移除。原因是新版本 autoprefixer 默认会清理"过时"的前缀,但某些样式仍需兼容旧版浏览器。解决方案:
javascript
// 在 postcss.config.js 中添加以下配置
autoprefixer({
// 保留老式flexbox语法,阻止移除-webkit-box相关属性
flexbox: 'no-2009',
// 不移除过时的前缀
remove: false,
});