首先介绍一下背景,我是19年初来公司,当时采用了最新的 vue-cli3 来作为工程脚手架,开放了vue-config.js 进行了一些简单的配置就开始了开发 时光飞逝,今年已经是第4个年头,公司还是使用的当年的技术,由于之前业务需求多,时间紧迫,所以就一直沿用了当时的技术到今天,尽管项目初期就采用了git submodule 的方式对基础组建,进行了封装,但是由于工程浩大,代码量已经数十万行,编译编译时间较长,且团队成员还在使用较为落后的技术,亟须进行技术改造升级,引入新技术,势在必行。
准备工作
- 切换node 版本
nvm use 20
- 替换 yarn.lock 中失效的镜像源地址 最新地址 registry.npmmirror.com
- 升级 chromedriver 升级到 129.0.4
1. 升级 vue-cli
npm remove vue-cli -g
npm add vue-cli -g
2. 执行 vue upgrade
vue upgrade
| 包名 | 当前版本 | 升级后版本 |
|---|---|---|
| @typescript-eslint/eslint-plugin | ^2.18.0 | ^5.4.0 |
| @typescript-eslint/parser | ^2.18.0 | ^5.4.0 |
| @vue/cli-plugin-babel | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-e2e-nightwatch | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-eslint | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-pwa | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-router | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-typescript | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-unit-mocha | ~4.2.0 | ~5.0.8 |
| @vue/cli-plugin-vuex | ~4.2.0 | ~5.0.8 |
| @vue/cli-service | ~4.2.0 | ~5.0.8 |
| @vue/eslint-config-standard | ^5.1.0 | ^6.1.0 |
| @vue/eslint-config-typescript | ^5.0.1 | ^9.1.0 |
| eslint | ^6.7.2 | ^7.32.0 |
| eslint-plugin-import | ^2.20.1 | ^2.25.3 |
| eslint-plugin-node | ^11.0.0 | ^11.1.0 |
| eslint-plugin-promise | ^4.2.1 | ^5.1.0 |
| eslint-plugin-vue | ^6.1.2 | ^8.0.3 |
| typescript: ~3.7.5 | ~4.5.5 |
3. 升级 core-js
yarn remove core-js
yarn add core-js
| 包名 | 当前版本 | 升级后版本 |
|---|---|---|
| core-js | ^3.6.4 | ^3.30.0 |
4. 向后兼容
// 视情况而定
// vue.config.js
configureWebpack: (config) => {
config.resolve.fallback = {
path: require.resolve('path-browserify'),
os: require.resolve('os-browserify/browser'),
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify')
}
}
// 视情况而定
yarn add path-browserify os-browserify crypto-browserify stream-browserify
5. vue-config.js 配置项变更
// vue-config.js
{
css: {
loaderOptions: {
postcss: {
postcssOptions: { // 原来不要这一级
plugins: [
require('postcss-pxtorem')({
rootValue: 10,
propList: ['*'], // 可以将 px 转换为 rem 的属性
selectorBlackList: [
/^html$/, // 如果是 regexp,它将检查选择器是否匹配 regexp,这里表示 html 标签不会被转换
'.px-', // 如果是字符串,它将检查选择器是否包含字符串,这里表示 .px- 开头的都不会转换
'el-time-'
], // px 不会被转换为 rem 的 选择器
minPixelValue: 2 // 设置要替换的最小像素值(2px会被转rem)。 默认 0
})
]
}
}
}
}
}
6. 修复 & 禁止 eslint typescript 报错
根据报错选择将对应规则关闭 or 修复对应的 eslint 报错
7. 升级 vue 版本及其相关依赖
- 由于vue2.x 与 vue3.x 不兼容,故而采用 vue 次新版本 vue2.7,既可以使用 vue3 的新语法,又可以保留原来 vue2 的旧写法
yarn remove vue
yarn add vue@^2.7.14
yarn remove element-ui
yarn add element-ui@^2.15.13
yarn remove vue-router
yarn add vue-router@^3.6.5
| 包名 | 当前版本 | 升级后版本 |
|---|---|---|
| vue | ^2.6.11 | ^2.7.14 |
| element-ui | ^2.4.5 | ^2.15.13 |
| vue-router | ^3.1.5 | ^3.6.5 |
8. 打包优化尝试
开始之前可以先安装两个小工具
speed-measure-webpack-plugin // 分析耗时的地方在哪里
webpack-bundle-analyzer // 分析拆包是否合理
- 增加 cache-loader(旧版本自带,新版本得自己装)
configureWebpack: config => { config.module.rules.forEach((rule, index) => {
if (rule.test.test('.vue') || rule.test.test('.ts') || rule.test.test('.tsx')) {
rule.use.unshift('cache-loader')
}
}
-
增加 fork-ts-checker 使用内存,cpu核数
// vue.config.js chainWebpack: config => { config .plugin('fork-ts-checker') .tap(args => { const totalmem = Math.floor(os.totalmem() / 1024 / 1024) // get OS mem size const allowUseMem = totalmem > 4096 ? 4096 : 1000 const opts = { memoryLimit: allowUseMem, workers: 4 } Object.assign(args[0], opts) return args }) } -
增加 thread-loader 启动多核打包
configureWebpack: config => {
config.module.rules.forEach((rule, index) => {
if (rule.test.test('.vue') || rule.test.test('.ts') || rule.test.test('.tsx')) {
rule.use[rule.use.length - 1].options.happyPackMode = true
rule.use.splice(rule.use.length - 1, 0, {
loader: 'thread-loader',
// loaders with equal options will share worker pools
options: {
// the number of spawned workers, defaults to (number of cpus - 1) or
// fallback to 1 when require('os').cpus() is undefined
workers: 2,
// number of jobs a worker processes in parallel
// defaults to 20
workerParallelJobs: 50,
// additional node.js arguments
workerNodeArgs: ['--max-old-space-size=2048'],
// Allow to respawn a dead worker pool
// respawning slows down the entire compilation
// and should be set to false for development
poolRespawn: false,
// timeout for killing the worker processes when idle
// defaults to 500 (ms)
// can be set to Infinity for watching builds to keep workers alive
poolTimeout: process.env.NODE_ENV === 'production' ? 2000 : Infinity,
// number of jobs the poll distributes to the workers
// defaults to 200
// decrease of less efficient but more fair distribution
poolParallelJobs: 50,
// name of the pool
// can be used to create different pools with elsewise identical options
name: 'my-pool' + index
}
})
}
})
- 若不用支持ie11, 则可以使用避免二次执行 vue-cli-service build 生成 bundle
vue-cli-service build --no-module
经测试除使用1, 4能显著提高打包编译时间以外,剩下的手段貌似效果都不明显 ╮(╯▽╰)╭
9. node-sass vs dart-sass
懂得都懂,node-sass 经常 GG,体验极度不好,而且官网也推荐了使用 dart-sass 代替 node-sass, 替换后亲测安装时间的确能够减少, 分 3 步骤走,话不多说直接上教程。
- 安装 dart sdk
- 去掉node-sass, 安装 sass
yarn remove node-sass
yarn add sass
- 全局替换 /deep/ to ::v-deep(部分警告可有时间慢慢解决)
10. es-lint error 错误
error Parsing error: Cannot read properties of undefined (reading 'map')
设置 vue.config.js, 临时解决 lintOnSave: false
11. path, process等在浏览器端无法使用
安装 node-polyfill-webpack-plugin,安装官方文档配置即可
结论
经过以上工程配置,项目初步运行起来了,但是优化之后的打包速度依然不是特别理想,这次先记录到这里,我会持续将优化进行下去,如果有人有更好的结果,也可以反馈给我。
thanks for watching (ง •̀_•́)ง