如何输出Webpack构建分析
输出Webpack构建信息的
.
json
文件:
webpack --profile --json > starts.json
说明:
-
--
profile
:记录构建中的耗时信息。
-
--
json
:以json格式输出构建结果,最后只输出一个json文件(包含所有的构建信息)。
web可视化查看构建分析
得到了webpack构建信息文件
starts
.
json
,如何进行很好的可视化查看?
1、可视化分析工具Webpack Analyse
Webpack Analyse是个在线Web应用,上传
starts
.
json
文件就可以。
2、webpack-bundle-analyzer
安装:
npm i -g webpack-bundle-analyzer
生成
starts
.
json
后,直接在其文件夹目录执行
webpack-bundle-analyzer
浏览器会打开对应网页并展示构建分析文档地址webpack-bundle-analyzer。
3、webpack-dashboard
webpack-dashboard是一款统计和优化webpack日志的工具,可以以表格形势展示日志信息。其中包括构建过程和状态、日志以及涉及的模块列表。
4、jarvis
jarvis是一款基于webapck-dashboard的webpack性能分析插件,性能分析的结果在浏览器显示,比webpack-bundler-anazlyer更美观清晰GitHub文档地址。
安装:
npm i
-D webpack-jarvis
webpack
.
config
.
js
配置:
const Jarvis = require("webpack-jarvis");
plugins: [
new Jarvis({
watchOnly: false,
port: 3001 // optional: set a port
})
];
参数说明:
-
port:监听的端口,默认1337,监听面板将监听这个端口,通常像http://localhost:port/。
-
host:域名,默认localhost,不限制域名。
-
watchOnly:仅仅监听编译阶段。默认为true,如果高为false,jarvis不仅仅运行在编译阶段,在编译完成后还保持运行状态。
-
界面:看到构建时间为:
Time
:
11593ms
(作为优化时间对比)。
webpack配置优化
webpack在启动时会从配置的Entry出发,解析出文件中的导入语句,再递归解析。
对于导入语句Webpack会做出以下操作:
-
根据导入语句寻找对应的要导入的文件;
-
在根据要导入的文件后缀,使用配置中的Loader去处理文件(如使用ES6需要使用babel-loader处理)。
针对这两点可以优化查找途径:
1、优化Loader配置
Loader处理文件的转换操作是很耗时的,所以需要让尽可能少的文件被Loader处理。
{
test: /\.js$/,
use: [
'babel-loader?cacheDirectory',//开启转换结果缓存
],
include: path.resolve(__dirname, 'src'),//只对src目录中文件采用babel-loader
exclude: path.resolve(__dirname,' ./node_modules'),//排除node_modules目录下的文件
},
2、优化resolve.modules配置
resolve
.
modules
用于配置webpack去哪些目录下寻找第三方模块,默认是
[
'node_modules'
]
,但是,它会先去当前目录的
./
node_modules
查找,没有的话再去
../
node_modules
最后到根目录。
所以当安装的第三方模块都放在项目根目录时,就没有必要安默认的一层一层的查找,直接指明存放的绝对位置。
resolve
: {
modules: [path.resolve(__dirname, 'node_modules')],
}
3、优化resolve.extensions配置
在导入没带文件后缀的路径时,webpack会自动带上后缀去尝试询问文件是否存在,而
resolve
.
extensions
用于配置尝试后缀列表;默认为
extensions
:[
'js'
,
'json'
]
。
当遇到
require
(
'./data'
)
时webpack会先尝试寻找
data
.
js
,没有再去找
data
.
json
;如果列表越长,或者正确的后缀越往后,尝试的次数就会越多。
所以在配置时为提升构建优化需遵守:
-
频率出现高的文件后缀优先放在前面。
-
列表尽可能的小。
-
书写导入语句时,尽量写上后缀名。
因为项目中用的
jsx
较多,所以配置
extensions
:
[
".jsx"
,
".js"
]
。
基本配置后查看构建速度:
Time
:
10654ms
,配置前为
Time
:
11593ms
。
使用DllPlugin优化
在使用webpack进行打包时候,对于依赖的第三方库,如react、react-dom等这些不会修改的依赖,可以让它和业务代码分开打包。
只要不升级依赖库版本,之后webpack就只需要打包项目业务代码,遇到需要导入的模块在某个动态链接库中时,就直接去其中获取;而不用再去编译第三方库,这样第三方库就只需要打包一次。
接入需要完成的事
-
将依赖的第三方模块抽离,打包到一个个单独的动态链接库中。
-
当需要导入的模块存在动态链接库中时,让其直接从链接库中获取。
-
项目依赖的所有动态链接库都需要被加载。
接入工具(webpack已内置)
-
DllPlugin插件:用于打包出一个个单独的动态链接库文件。
-
DllReferencePlugin:用于在主要的配置文件中引入
DllPlugin
插件打包好的动态链接库文件。
配置webpack_dll.config.js,构建动态链接库
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
mode: 'production',
entry: {
// 将React相关模块放入一个动态链接库
react: ['react','react-dom','react-router-dom','react-loadable'],
librarys
: ['wangeditor'],
utils: ['axios','js-cookie']
},
output: {
filename: '[name]-dll.js',
path: path.resolve(__dirname, 'dll'),
// 存放动态链接库的全局变量名,加上_dll_防止全局变量冲突
library: '_dll_[name]'
},
// 动态链接库的全局变量名称,需要可output.library中保持一致,也是输出的manifest.json文件中name的字段值
// 如react.manifest.json字段中存在"name":"_dll_react"
plugins: [
new DllPlugin({
name: '_dll_[name]',
path: path
.join(__dirname, 'dll', '[name].manifest.json')
})
]
}
webpack.pro.config.js中使用
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
...
plugins: [
// 告诉webpack使用了哪些动态链接库
new DllReferencePlugin({
manifest: require('./dll/react.manifest.json')
}),
new DllReferencePlugin({
manifest: require('./dll/librarys.manifest.json')
}),
new DllReferencePlugin({
manifest: require('./dll/utils.manifest.json')
}),
]
注意:在
webpack_dll
.
config
.
js
文件中,
DllPlugin
中的name参数必须和
output
.
library
中的一致;因为
DllPlugin
的name参数影响输出的
manifest
.
json
的name;而
webpack
.
pro
.
config
.
js
中的
DllReferencePlugin
会读取
manifest
.
json
的name,将值作为从全局变量中获取动态链接库内容时的全局变量名。
执行构建
-
webpack
--
progress
--
colors
--
config
./
webpack
.
dll
.
config
.
js
-
webpack
--
progress
--
colors
--
config
./
webpack
.
prod
.
js
html中引入dll.js文件。
构建时间对比:
[
"11593ms"
,
"10654ms"
,
"8334ms"
]
。
HappyPack并行构建优化
核心原理:将webpack中最耗时的loader文件转换操作任务,分解到多个进程中并行处理,从而减少构建时间。
接入HappyPack:
-
安装:
npm i
-
D happypack
。
-
重新配置
rules
部分,将
loader
交给
happypack
来分配。
代码:
const HappyPack = require('happypack'
);
const happyThreadPool = HappyPack.ThreadPool({size: 5}); //构建共享进程池,包含5个进程
...
plugins: [
// happypack并行处理
new HappyPack({
// 用唯一ID来代表当前HappyPack是用来处理一类特定文件的,与rules中的use对应
id: 'babel',
loaders: ['babel-loader?cacheDirectory'],//默认设置loader处理
threadPool: happyThreadPool,//使用共享池处理
}),
new HappyPack({
// 用唯一ID来代表当前HappyPack是用来处理一类特定文件的,与rules中的use对应
id: 'css',
loaders: [
'css-loader',
'postcss-loader',
'sass-loader'],
threadPool: happyThreadPool
})
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: ['happypack/loader?id=babel'],
exclude: path.resolve(__dirname,' ./node_modules'),
},
{
test: /\.(scss|css)$/,
//使用的mini-css-extract-plugin提取css此处,如果放在上面会出错
use: [