一、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'],
}
}