因为项目过于庞大,有组内的小伙伴有人抱怨项目启动太慢啦。所以这个事得办。抓紧办。
期间考虑要不要升一下webpack5,其实webpack5在其他项目中已经升级过,对于项目的打包速度没有什么提升,只是内置了一些类似于缓存hard-source-webpack-plugin插件、file-loader等,ps: 我对webpack5的关注点在于模块联邦,实现不同项目间组件复用、微前端这些。。。
所以就拿着webpack4开搞吧。
1. 包体积
ps: 包的体积减小自然会使构建的速度有所提升
包体积分析插件 BundleAnalyzerPlugin
BundleAnalyzerPlugin配置入webpack中会自动生成打开包分析页面localhost:8888;
plugins: [
new HtmlWebpackPlugin({ template: './index.html' }),
// HMR
new webpack.HotModuleReplacementPlugin(),
// new CleanWebpackPlugin(['public']),
new CopyWebpackPlugin([{
from: './src/assets',
}]),
new MiniCssExtractPlugin({
filename: 'vender.css',
chunkFilename: '[name].css',
}),
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/),
new WebpackBar({
color: '#0096f5',
name: 'frontend',
}),
new OpenBrowserPlugin({ url: 'http://localhost:7878' }),
new BundleAnalyzerPlugin({ analyzerHost: 'localhost' }),
],
启动项目的同时 会打开这样一个页面
拆包前的包体积分析
当然我们不想每次启动项目就展开包体积分析,所以我们给他一个其他的启动命令,只有运行这个启动命令时再进行包分析
"scripts": {
"visu": "NODE_ENV=visu node script/prod-build",
},
// 运行 yarn visu的时候将node环境设为visu 并运行script文件夹下的prod-build文件
// 那么主要的逻辑就在prod-build.js文件中了
// prod-build.js主要是修改node变量、合并BundleAnalyzerPlugin和webpack的其他插件、运行webpack。
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const browserConfig = require('../webpack.prod');// 拿到webpack的主要配置项
if (process.env.NODE_ENV === 'visu') { //当环境是visu的时候添加BundleAnalyzerPlugin插件
browserConfig.plugins.push(new BundleAnalyzerPlugin({ analyzerHost: 'localhost' }));
}
// Webpack compile in a try-catch
function compile(config) {
let compiler;
try {
compiler = webpack(config);
} catch (e) {
console.log('error');
process.exit(1);
}
return compiler;
}
const clientCompiler = compile(browserConfig);// 启动webpack编译
clientCompiler.run((err) => {
if (err) {
console.error(err);
}
});
// 这样就通过yarn vis能够给编译的webpack加入BundleAnalyzerPlugin
// 命令运行时自动打开包分析页面了
有了包分析,我们就可以进行包的拆分了
拆包好处太多了:打包速度快、公共包拎出来避免每次编译、按需加载、首评打开速度提升。。。
拆包
// webpack4和5都可以通过optimization的splitChunks来做
// 其实也可以用dllplugin(webpack3时代用的比较多这次就不用了,因为有更好的)
optimization: {
splitChunks: {
minSize: 30720, // 超过30K分包
maxSize: 102400, // 分包最大100K超出再分包
minChunks: 1,
maxAsyncRequests: 6,
maxInitialRequests: 4,
cacheGroups: {
'react-vendor': {
test: module => /react/.test(module.context) || /classnames/.test(module.context) || /mobx/.test(module.context),
priority: 4,
reuseExistingChunk: true,
name: 'react',
},
'antd-vendor': {
test: module => (/antd?/.test(module.context)),
priority: 3,
reuseExistingChunk: true,
name: 'antd',
},
'xlsx-vendor': {
test: /xlsx/,
priority: 1,
reuseExistingChunk: true,
name: 'xlsx',
},
'lodash-vendor': {
test: /lodash/,
priority: 2,
reuseExistingChunk: true,
name: 'lodash',
},
vendors: {
name: 'chunk-vendors', // 优先级小于output.filename
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
这样在包分析页就可以看到,很多的模块的公共的包被抽离了出来,且没有了大体积的文件
(在这个项目中 体积由30.2M变成了6.74M,优化到原来的四分之一多)
拆包后的包体积分析
2. 构建速度
构建速度提升的点可太多了,代码写质量都会有影响,在webpack中构建的速度很受打包文件数量和编译的loader限制。
要提升构建的速度,我们首先得知道当前webpack打包的时常是多少,这里用到的是speed-measure-webpack-plugin插件
打包速度分析(speed-measure-webpack-plugin)
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({ // smp.wrap()包一下webpack的配置即可
entry: ['src/index.js'],
output: {
path: resolve('public'),
filename: 'vender.js',
chunkFilename: '[name].js',
publicPath: '/',
},
resolve: {
alias: {
src: resolve('src'),
assets: resolve('src/assets'),
components: resolve('src/components'),
style: resolve('src/static/style'),
},
},
。。。。
打包速度优化前
以上这个日志可能被其他webpack日志顶没,最好在命令行查看,别在编辑器中找
打包速度优化
打包速度优化主要用的是开启多进程、开启缓存功能
- 开启多进程用的是thread-loader(happy-pack插件也可以用,但是已经不再维护了)
const threadLoader = require('thread-loader');
const jsWorkerPool = {
// options
// 产生的 worker 的数量,默认是 (cpu 核心数 - 1)
// 当 require('os').cpus() 是 undefined 时,则为 1
workers: 2,
// 闲置时定时删除 worker 进程
// 默认为 500ms
// 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
poolTimeout: 2000,
};
const cssWorkerPool = {
// 一个 worker 进程中并行执行工作的数量
// 默认为 20
workerParallelJobs: 2,
poolTimeout: 2000,
};
// 可以通过预热 worker 池(worker pool)来防止启动 worker 时的高延时
threadLoader.warmup(jsWorkerPool, ['babel-loader']);// js文件的预热
threadLoader.warmup(cssWorkerPool, ['css-loader', 'sass-loader']);// css文件的预热
module.exports = smp.wrap({
module: {
rules: [
{
test: /\.(js)$/,
exclude: /(node_modules)/,
use: [
{
loader: 'thread-loader',// 开启多个work,使用预热的配置
options: jsWorkerPool,
},
{
loader: 'babel-loader',
options: {
babelrc: true,
},
},
],
},
{
test: /\.(scss|css)$/,
use: [
'css-hot-loader',
MiniCssExtractPlugin.loader,
{
loader: 'thread-loader',// 开启多个work,使用预热的配置
options: cssWorkerPool,
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
'sass-loader',
],
},
......
- 开启缓存,加快二次启动速度
webpack 自带cache缓存,但是有更牛的hard-source-webpack-plugin
hard-source-webpack-plugin 为模块提供中间缓存步骤(首次加载很慢,但以后的构建很快)
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
plugins: [
new HardSourceWebpackPlugin(),
],
我们来看下此时的打包速度
image.png
还有其他的一些优化类似于loader的exclude/include的使用、extends的合理使用、alias的使用。。。。巴拉巴拉的。。。就不多赘述了
网友评论