提升webpack性能优化无非从两个方面入手:
1.如何构建速度
2.如何优化打包后的文件
如何文件构建速度
webpack构建的过程,其实是把,从入口开始,通过AST语法树分析,把所有依赖的模块,结合loader和plugin,都进行内容转换,合并在一起,最终输出打包文件的过程。
所以,要提高构建速度,就要减少不必要的模块依赖,和loader、plugin的使用和其他提升速度的办法等等
1.减少不必要的模块依赖
module.noParse
字段可用于配置不需要解析的模块。对于类似jquery和lodash这些大型的第三方库,本身就是兼容性非常好的,不需要在进行解析。可以忽略以提升构建速度。
module.exports = {
// ...
module: {
noParse: /jquery|lodash/, // 正则表达式
// 或者使用 function
noParse(content) {
return /jquery|lodash/.test(content)
},
}
}
2.减少不必要的loader处理
使用loader的时候尽可能考虑不需要处理的模块,以提升构建速度。
通过module.rule.exclude
或module.rule.include
排除或仅包含需要应用loader的场景。
例如:
rules: [
{
test: /\.js$/,
exclude: /node_modules/, //不匹配
loader: "eslint-loader",
},
{
test: /\.js$/,
include: /src/, //匹配
loader: "babel-loader",
},
],
eslint-loader是代码规范检测的loader,所以没必要也不需要去匹配/node_modules下的模块。
babel-loader是为了吧es6和更高版本的语法转换为es3或者es5的语法。假设/src下都是自定义的模块,所以只需要转换自己写的模块就好
3.通过配置区分生产环境和开发环境的plugin,不要混用,导致影响构建速度。
4.使用cache-loader进行缓存文件。
对于一些比较消耗性能的模块,并且打包后文件内容没有改动可以使用cache-loader进行缓存。因为缓存是直接保存在硬盘,所以存取缓存都是要消耗一定的性能。小文件没必要缓存。下次就可以不使用loader而使用缓存。
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'cache-loader',
options: {
cacheDirectory: path.resolve('.cache') //还能进行配置
}
},
'babel-loader'
],
include: path.resolve('src')
}
]
}
}
5.开启多线程构建
webpack是基于node.js运行的,而node.js是单线程的,所以webpack处理文件是一个个处理的,如果需要处理的文件一多的话,处理速度会很慢,因此在需要解析大量文件的项目中,可以通过开启多线程来处理文件,以加快构建速度。
- loader
如thread-loader
会开启一个线程池,线程池中包含适量的线程,利用多线程同时开启多个loader的处理
// webpack.config.js 文件配置
module.exports = {
mode: "development",
module: {
rules: [
{
test: /\.js$/,
use: [
"thread-loader",
"babel-loader"
]
}
]
}
};
- plugin
可以使用happypack
是一个开启多线程解析和构建文件的plugin。
var HappyPack = require('happypack')
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
module.exports = {
mode: "development",
plugins: [
new HappyPack({
id: 'js',
loaders: ['babel-loader'],
// 用于检索工作线程的预定义线程池
threadPool: happyThreadPool,
// 启用此选项可将状态消息从HappyPack记录到STDOUT
verbose: true
})
]
开发阶段的页面响应速度
当webpack开启watch,当文件被修改后,webpack会自动构建输出新的打包文件,但是还需要刷新浏览器重载页面才能看到最新的内容,这样的会降低开发效率。webpack-dev-server
正好适用于处理类似的问题。webpack-dev-server
的热更新
和热替换
功能能提高我们开发阶段的页面响应速度。
1.热更新
热更新可以理解为当文件有修改,页面会实时刷新。原理是,webpack-dev-server使用的是express框架作为文件资源的http服务器,通过websoket协议和浏览器端进行通讯。当文件修改的时候,http服务器会监听到文件变化,而触发webpakc编译文件,但是文件内容不会输出到output的目录,而是把编译的内容存放到内存中,然后浏览器就会实时更新内存中的内容,实现页面实时更新。
2.热替换HMR(Hot Module Replacement)
热更新是把整个页面刷新,而热替换是只刷新修改的那部分。css样式修改可以立马看到热替换效果,因为css只是样式。而如js这些逻辑性的代码,无法页面热替换,除了css文件都需要额外的手动处理才能热替换。
// webpack.config.js
const webpack = require('webpack')
module.exports = {
// ...
devServer: {
// 开启 HMR 特性,如果资源不支持 HMR 会 fallback 到 live reloading
hot: true
// 只使用 HMR,不会 fallback 到 live reloading
// hotOnly: true
},
plugins: [
// ...
// HMR 特性所需要的插件
new webpack.HotModuleReplacementPlugin()
]
}
具体热更新和热替换参考:https://blog.csdn.net/ganle/article/details/106455612
如何优化打包后的文件
打包后的文件最优的结果就是文件尽可能少、文件尽可能小,所以只需要根据这两个方向去优化。
1.模块分离
模块分离就是将一个整体的代码,分布到不同的打包文件中去,目的就是为了减少公共代码,降低打包文件总体积,特别是对于一些大型的第三方库,使用.模块分离还能充分利用浏览器缓存去加载这些公共模块,不用每次都去请求,利于传输速度。当多个chunk引入了公共模块的时候,webpack默认是不分离模块的,这样就会造成代码重复,所以当多个chunk引入了公共模块或者公共模块体积比较大,或者公共模块较少变动的时候,可以使用分包。
分包有两种方式:手动分离和自动分离
-
手动分离
手动分包就是开发人员通过根据分析模块的依赖关系,把公共模块通过打包或手动放到一个公共文件夹里,被打包后的index.html文件引入到页面。
大致步骤:
(1)提取公共模块到公共文件夹,并生成资源清单列表(可以手动创建,也可以使用webpack内置插件DllPlugin
生成)
(2)在html页面引入公共模块
(3)使用DllReferencePlugin
控制chunk打包结果,资源清单里面有的模块,不在打包进入bundle里面。 -
自动分离
自动分离相对于手动分离会方便一点,只需要配置要分离策略。
webpack提供了optimization配置项,用于配置一些优化信息
其中splitChunks是分离模块策略的配置
module.exports = {
optimization: {
splitChunks: {
// 分包策略
chunks: 'all',
}
}
}
使用以上chunks
为all
,就可以满足大部分的场景了。
具体细节参考:
https://blog.csdn.net/xun__xing/article/details/108312321
https://webpack.docschina.org/plugins/split-chunks-plugin/
2.代码压缩
webpack自动集成了Terser
插件进行打包时代码压缩,只需要配置optimization
选项即可
//压缩js
const TerserPlugin = require('terser-webpack-plugin');
//压缩css
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
}
]
},
optimization: {
// 是否要启用压缩,默认情况下,生产环境会自动开启
minimize: true,
minimizer: [ // 压缩时使用的插件,可以有多个
new TerserPlugin(),
new OptimizeCSSAssetsPlugin()
],
},
};
3.删除无用的代码和模块
webpack2开始内置Tree-Shaking
功能来删除用不到或者对程序没有影响的代码,极大的减少了打包后的体积。tree-shaking是基于es6的,因此对于一些使用commonJs导出的第三方库如lodash,应该换成es6方式导出的版本,这样才能使用tree-shaking优化。
更多详情参看:https://juejin.cn/post/6844903544756109319
4.模块懒加载
对于一些不会立即使用的模块,可以通过懒加载的形式导入import('xxx')
,webpack打包的时候会把这些需要懒加载的模块打包成独立的文件,只有当使用到的时候才会去加载这个文件,并把模块添加到webpackJsonp对象中。
更多参考:https://blog.csdn.net/qq_38888512/article/details/116448683
其他优化相关
1.使用webpack Bundle Analyzer
作为模块打包分析
webpack Bundle Analyze分析工具
2.使用compression-webpack-plugin
进行预压缩成gzip
compression-webpack-plugin进行压缩
前端优化gzip传输