一、webpack 构建速度和体积优化的高版本设置、多进程多实例构建、多进程多实例并行压缩、预编译资源模块、缓存优化速度和缩小构建目标
- 构建速度优化,使用高版本的
webpack 和 Node.js,构建时间降低了 60% - 98%。使用 webpack4 的优化原因,如下所示:
V8 带来的优化,for of 替代 forEach、Map 和 Set 替代 Object、includes 替代 indexOf 等等- 默认使用更快的
md4 hash 算法 webpack AST 可以直接从 loader 传递给 AST,减少解析时间- 使用字符串方法替代正则表达式
- 多进程/多实例构建,资源并行解析可选方案,
thread-loader、parallel-webpack、HappyPack 等等。 - 多进程/多实例,使用
HappyPack 解析资源,原理是每次 webpack 解析一个模块,HappyPack 会将它及它的依赖分配给 worker 线程中,代码如下:
export.plugins = [
new HappyPack({
id: 'jsx',
threads: 4,
loaders: ['babel-loader']
}),
new HappyPack({
id: 'styles',
threads: 2,
loaders: ['style-loader', 'css-loader', 'less-loader']
})
];
- 多进程/多实例,使用
thread-loader 解析资源,原理是每次 webpack 解析一个模块,threa-loader 会将它及它的依赖分配给 worker 线程中,代码如下:
module.exports = smp.wrap({
entry: entry,
output: {
path: path.join(_dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
mode: 'production',
module: {
rules: [
{
test: /.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 3
}
},
'babel-loader',
]
}
]
}
})
- 多进程/多实例的并行压缩,如下所示:
- 使用
parallel-uglify-plugin 插件,代码如下:
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
plugins: [
new ParallelUglifyPlugin({
uglifyJS: {
output: {
beautify: false,
comments: false,
},
compress: {
warnings: false,
drop_console: true,
collapse_vars: true,
reduce_vars: true
}
}
})
]
};
uglifyjs-webpack-plugin 开启 parallel 参数,代码如下:
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
mangle: true,
output: null,
toplevel: false,
nameCache: null,
ie8: false,
keep_fnames: false
},
parallel: true
})
]
};
terser-webpack-plugin 开启 parallel 参数,代码如下:
const TerserWebpackPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserWebpackPlugin({
parallel: 4
})
]
}
};
- 分包,设置
Externals,思路是将 react、react-dom 基础包通过 cdn 引入,不打入 bundle 中,方法是使用 html-webpack-externals-plugin。 - 对于进一步分包,预编译资源模块,思路是将
react、react-dom、redux、react-redux 基础包和业务基础包打包成一个文件,方法是使用 DLLPlugin 进行分包,DllReferencePlugin 对 manifest.json 引用,代码如下:
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: process.cwd(),
resolve: {
extensions: ['.js', '.jsx', '.json', '.less', '.css'],
modules: [_dirname, 'node_modules']
},
entry: {
library: [
'react',
'react-dom',
'redux',
'react-redux'
]
},
output: {
filename: '[name].dll.js',
path: path.resolve(_dirname, './build/library'),
library: '[name]'
},
plugins: [
new webpack.Dllplugin({
name: '[name]',
path: './build/library/[name].json'
}}
]
};
- 使用
DllReferencePlugin 引用 manifest.json,在 webpack.config.js 引入,代码如下:
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require('./build/library/manifest.josn')
})
]
};
- 缓存的目的是提升二次构建速度,缓存思路,如下所示:
babel-loader 开启缓存terser-webpack-plugin 开启缓存- 使用
cache-loader 或者 hard-source-webpack-plugin
- 缩小构建目标,目的是尽可能的少构建模块,比如
babel-loader 不解析 node_modules,代码如下:
module.exports = {
rules: {
test: /\.js$/,
loader: 'happypack/loader',
exclude: 'node_modules'
}
}
- 减少文件搜索范围,优化
resolve.modules 配置,减少模块搜索层级,优化 resolve.mainFields 配置,优化 resolve.extensions 配置,合理使用 alias,代码如下:
module.exports = {
resolve: {
alias: {
react: path.resolve(_dirname, './node_modules/react/dist/react.min.js'),
},
modules: [path.resolve(_dirname, 'node_modules')],
extensions: ['.js'],
mainFields: ['main'],
}
}