项目升级到webpack5
为什么升级到 webpack5
由于公司的后台项目比较大,构建时间非常久。就想着试试升级到 webpack5 情况下能带来多大的优化。
至于 webpack5 相对 webpack4 有哪些提升,官方也给出了说明:
- 尝试用持久性缓存来提高构建性能。
- 尝试用更好的算法和默认值来改进长期缓存。
- 尝试用更好的 Tree Shaking 和代码生成来改善包大小。
- 尝试改善与网络平台的兼容性。
- 尝试在不引入任何破坏性变化的情况下,清理那些在实现 v4 功能时处于奇怪状态的内部结构。
- 试图通过现在引入突破性的变化来为未来的功能做准备,使其能够尽可能长时间地保持在 v5 版本上
TIP
由于本项目当初是基于 vue-cli 创建的,所以本次升级也是先使用 vue-cli 创建一个基于 webpack5 的模板。
webpack的版本由4.46.0 升级至5.75.0
前提准备
webpack-bundle-analyzer
这是一个可以审查打包后的体积分布的插件,构建运行后可以可视化的看到每个模块打包的依赖内容,进而进行相应的构建包体积优化;
npm i webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzerPlugin(),
]
speed-measure-webpack-plugin
这是一个打包构建耗时分析插件;
npm i webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzerPlugin(),
]
TIP
使用时,需要将此插件放在最后。
升级过程遇到的问题
配置全局 scss 变量和 mixin
由于使用了较新版本的 sass-loader ,所以配置项有所改变
module.exports = defineConfig({
css: {
loaderOptions: {
sass: {
additionalData: '@import "@/styles/color.scss";',
},
},
}
})
Module not found: Error: Can't resolve 'crypto'
这是因为缺少一些使用到的 node 模块。
最开始,Webpack 目标是允许在浏览器中运行 Node 模块。但是现在在 Webpack 看来,大多模块就是专门为前端开发的。在 v4 及以前的版本中,对于大多数的 Node 模块会自动添加 polyfill 脚本,polyfill 会加到最终的 bundle 中,其实通常情况下是没有必要的。在 v5 中将停止这一行为。
方法一
根据提示在 webpack.config.js里面配置
module.exports = {
resolve: {
crypto: require.resolve('crypto-browserify')
}
}
如果是vue-cli,则是在vue.config.js
module.exports = defineConfig({
configureWebpack: {
resolve: {
crypto: require.resolve('crypto-browserify')
}
},
})
方法二 使用NodePolyfillPlugin
如果觉得一个个引入很麻烦,也可以使用插件引入
vue.config.js
module.exports = defineConfig({
configureWebpack: {
plugins: [new NodePolyfillPlugin()]
},
})
Can't resolve 'fs'
缺少 fs
module.exports = defineConfig({
configureWebpack: {
externals: {
fs: require('fs'),
},
},
})
scss 不支持 exports
把需要导出变量的 scss 文件 改成 xx.module.scss,然后引入。
import $style from '@/xxx.module.scss'
Using / for division is deprecated and will be removed in Dart Sass 2.0.0.
所有 sass 报错均指向 elment-ui 的主题颜色修改,这是因为 sass 一些高级版本已经不再支持一些语法,所以我们需要降低 sass 的版本。
npm i sass@1.30.0 -D
启动
配置前 首次项目启动时间为 44892ms; 二次项目启动时间为 23221ms
开启缓存
二次启动时间减少到 3121ms
module.exports = defineConfig({
configureWebpack: {
cache: {
type: 'filesystem', //默认为memory,也就是存储到内存
buildDependencies: {
config: [__filename],
},
},
}
})
thread-loade
这是一个多进程构建打包的 loader,能够极大提高构建的速度,只要将 thread-loader 放在构建耗时较大的 loader 之前,比如 babel-loader 等。
npm i thread-loader -D
{
test: /\.js$/,
include: path.resolve('src'),
exclude: /node_modules/,
use: ['thread-loader', 'babel-loader'],
},
打包
打包优化
splitChunks 分包
分包思路基本就围绕着两点:
- 缩小体积,减少重复
- 利于缓存,即不变和变要区分开
- 由于本项目所有的 api 都是写在 api 文件下,所以可以对其进行打包成单独模块。避免其重复打包进不同页面。
api: {
name: 'api',
test: /[\\/]api[\\/]/,
priority: 7,
},
- 本项目的自写工具库 utils 同上,并且由于工具库不常变,更有利于缓存
utils: {
name: 'chunk-utils',
priority: 7,
test: /[\\/]utils[\\/]/,
}
- 将比较大的库单独打成一个模块,有利于缓存和分解模块,避免node_modules 模块过大
提取 element-Ui
elementUI: {
name: 'chunk-elementUI',
priority: 20,
test: /[\\/]node_modules[\\/]_?element-ui(.*)/,
},
提取 echarts
echarts: {
name: 'chunk-echarts',
priority: 20,
test: /[\\/]node_modules[\\/]_?echarts(.*)/,
},
- 将剩余的 node_modules 单独打成一个模块,有利于缓存
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial',
},
- 将组件单独打包成一个模块,理由同上
commons: {
name: 'chunk-commons',
test: /[\\/]layout[\\/]|[\\/]components[\\/]/,
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
关闭 Source Map
发现在打包后的文件存在 source Map 文件。一般在生产环境中时不需要 source Map 文件,避免暴露出代码。
optimization: {
devtool: process.env.NODE_ENV === 'production' ? false : 'eval-cheap-module-source-map',
}
也可以使用vue-cli的配置
module.exports = defineConfig({
productionSourceMap: false,
})
大家可以根据自己得需求进行配置。
对比
在 source Map 都关闭的情况下,打包体积对比:
配置前 16.5
配置后 14.8