「本文正在参与技术专题征文Node.js进阶之路,点击查看详情」
提升webpack打包速度
1、 升级打包工具的版本,跟上技术的迭代
-
升级
webpack、node、npm,yarn版本;
2、 在尽可能少的模块上使用loader; 降低loader作用范围,可以提升性能。
- 添加
exclude:/node_modules/,避免node_modules下面的js模块使用loader; - 或者
include
3、 尽量少的使用plugin,且使用靠谱的plugin
使用官方推荐的,社区验证过的的好用的插件。
比如在开发环境dev环境
- 不必使用
MiniCssExtractPlugin插件提取css文件; - 不必使用
OptimizeCssAssetsPlugin来压缩css文件;
4、 resolve 参数合理配置
resolve参数合理配置,配置过多会造成性能问题
resolve参理配置示例
resolve: {
// extensions 配置的时候一般只配置js之类的逻辑类的扩展名,对于css和json这种是不配置的。
extensions: ['.js', '.jsx'], // 可以省略引入时的后缀名
mainFiles:['index', 'child'] // ./child/默认会引入index.js
alias: { // 模块别名
// 默认导入child的时候会自动引入到配置
child: path.resolve(__dirname, '../src/child')
}
}
extensions
如果多个文件共享相同的名称但具有不同的扩展名,webpack 将解析具有数组中第一个列出的扩展名的文件并跳过其余文件
mainFiles
解析目录时要使用的文件名。一般情况下都不会配置多个。。。
alias
创建 import 或 require 的别名,来确保模块引入变得更简单
5、使用 DllPlugin 提高打包速度
DllPlugin 和 DllReferencePlugin 用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度。"DLL" 一词代表微软最初引入的动态链接库。
目标:第三方模块只打包一次
每次打包的时候,第三方模块(lodash、react)都需要从node_modules取出模块,然后在打包到源代码中。
我们在第一次打包的时候,将第三方模块打包代码存起来,之后直接用。
1)配置webpack.dll.js
将第三方文件单独打包生成dll.js,再用library通过全局变量的方式暴露出去;
// webpack.dll.js
module.exports = {
entry: {
vendor: [
'react',
'react-dom',
'react-router',
'redux',
'react-redux',
'redux-thunk',
'superagent',
'classnames',
'prop-types',
'pubsub-js',
'rxjs',
'lodash',
],
},
output: {
// filename: '[name]_dll_[chunkhash].js',
path: path.join(__dirname, '..', 'assets', 'dll'),
library: '_dll_[name]', // 把第三方的代码通过全局变量的方式暴露出去
},
};
// package.json
{
//...
"scripts": {
//...
"dll": "cross-env NODE_ENV=production webpack --config webpack/webpack.dll.js --progress",
}
}
运行npm run dll这样我们的第三方包 打包就打包到 dll 目录下
接下来就需要 把我们打包生成的dll 文件引入到项目中
需要使用到 add-asset-html-webpack-plugin
2) add-asset-html-webpack-plugin
借助addAssetHtml插件是往html文件中插入已经打包好的dll.js 文件
add-asset-html-webpack-plugin 往静态资源添加内容
- 安装
npm install add-asset-html-webpack-plugin --save - 使用 AddAssetHtmlPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const webpackConfig = {
entry: 'index.js',
output: {
path: 'dist',
filename: 'index_bundle.js',
},
plugins: [
new HtmlWebpackPlugin(),
new AddAssetHtmlPlugin({
filepath: require.resolve('./dll/vendors.dll.js')
}),
],
};
3) new webpack.DllPlugin()
借助DllPlugin插件对dll.js文件进行分析,生成mainfest.josn映射文件
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json')
}) // 映射文件
]
)
4) new webpack.DllReferencePlugin()
2)配置webpack.common.js (借助DllReferencePlugin插件进行分析,第二次打包直接取之前的dll.js )
文件使用引入模块时,使用引入dll中模块
// wbapack.common.js
new webpack.DllReferencePlugin({
manifest: ''// 路径
})
第三方模块的dll node批量化插件配置
在大型项目中,我们生成的第三方模块的dll.js文件会很多,如何动态添加plugin?
如下图有两套dll文件,还可能更多
此时一个个配置,就显得特别的麻烦,如下图这样
这里我们可以使用Node.js 批量化插件配置
const plugins = [];
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
if (/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolvel(__dirname, "../dll", file)
})
}
if (/.*\.mainfest.js/.test(file)) {
plugins.push(new DllReferencePlugin({
filepath: path.resolvel(__dirname, "../dll", file)
})
}
})
6、控制包文件大小
使用文件压缩
treeShaking或者optimizion.splitChunks分割代码
7、多进程打包
webpack 4 的版本 默认是单进程打包,
可以用插件thread-loader和parallel-webpack、happypack等多进程打包;
happyPack 多进程打包
const HappyPack = require('happypack')
// 步骤1 module.rules下-将对.js的文件交给id为label的HappyPack实例
{
test: /\.js$/,
use: ['happypack/loader?id=babel']
}
// 步骤2 happyPack开启多进程打包
new HappyPack({
// 用唯一的标识符 id 来代表当前的HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理.js 文件,用法和Loader 配置一样
loaders: ['babel-loader?cacheDirectory']
})
thread-loader
把这个 loader 放置在其他 loader 之前, 放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行
8、 合理使用sourceMap:
不同的环境使用不同的sourceMap配置来生成代码调试的文件
一方面能发现代码中出错的位置
另一方面还能提高打包时间
9、结合stats分析打包结果
使用weback-bundle-anlyzer插件可以分析打包结果;通过分析打包流程,可以优化打包;
10、开发环境内存编译:
使用webpackDevServer,打包出的文件放在内存中
11、开发环境无用插件剔除:
开发环境mode设置为development
12、ParallelUglifyPlugin 多进程压缩JS
- webpack 内置 Uglify 工具压缩JS
- JS单线程,开启多进程压缩更快
- 和happyPack 同理
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
const ParallelUglifyPlugin = require('ParallelUglifyPlugin')
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
// (还是使用 UglifyJS 压缩,只不过帮助开启了多进程)
uglifyJS: {
output: {
beautify: false, // 最紧凑的输出
comments: false // 删除所有的注释
},
compress: {
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true
}
}
})
复制代码
关于开启多进程
- 项目较大,打包较慢,开启多进程能提高速度
- 项目较小,打包很快,开发多进程会降低速度(进程开销)