打包结果分析
chunks即代码块,即webpack把js分割成了几块代码
module模块,每一个文件即一个模块
如何获取可视化的打包结果分析
官方
1.Mac:webpack --profile --json >stats.json
2.Window:webpack --profile --json | Out-file 'stats.json' --Encoding OEM
(在window中用Mac的那一套有用,用第二种方法无效,不知道为什么)
社区版本
1.webpack-bundle-analyzer
在命令行中运行:(运行后是什么都不会发生的,这是正常的)
webpack --profile --json >stats.json
然后就会在项目文件夹的根目录(不是在打包文件夹dist中)中有一个stats.json文件
这个文件中就会有这次打包的结果分析。
在一些大公司往往会把这个json文件上传出来,然后作为工具链流的监控,如果我们要调控的话,就会上传到后台,后台会有一个分析服务,对这个做一个监控。
json文件还是不太直观,可以上一个网站http://webpack.github.io/analyse/
上传这个json文件,就会生成一个可视化的界面。
点击chunks就可以看到每一个chunks的详情。点击module,这个会我们经常会查看的,看模块之间的依赖关系是不是按照我们想的去写的。
点击hints会有优化建议,但是所有项目他都会提示:Module in multiple chunks。所以可以忽略。但是可以在这个界面可以看到每个文件的打包时间。
对于社插件webpack-bundle-analyzer
npm install webpack-bundle-analyzer --save
在webpack.config.js中
const wba=require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
在注册webpack plugins的地方
new wba()
然后在打包之后,会自动弹出一个网页,内面是分析结果
我们打包结果分析主要看两个方面
- 看module的依赖有没有错
- 看chunks打包的是不是你想要的东西以及各个文件的打包时间,时间太长可以针对性的进行优化。
优化打包速度
有哪些可以优化的点
-
项目本身
1.减少文件依赖嵌套深度
2.使用尽可能少的处理
(尽可能少用loader和plugin,他们的处理都是很花时间的,有些是可以避免的,比如雪碧图的处理功能不是很好,我们可以自己制作) - webpack层面
-
DLL处理
(我们打包会生成vender第三方的包,我们一般不会去改变第三方的代码,我们一般改变我们的业务代码比如app.bundle.js。所以可以先把vendor生成好,下次就可以直接拿来用了,这样就减少了对vender的处理时间)
webpack也给了我们这样的解决方案:用到了两个webpack自带的库: 在webpack 注册plugins的地方
//例如你项目中用了jQuery和loadsh
new webpack.DllReferencePlugin({
manifest:require('./src/dll/jquery.json')
}),
new webpack.DllReferencePlugin({
manifest:require('./src/dll/loadsh.json')
}),
//这两个引入的文件和之后
//用webpack.dll.js打包生成的文件对应
然后在webpack.config.js同级目录下建立一个webpack.dll.js文件
webpack.dll.js:
const webpack=require("webpack");
module.exports={
entry:{
// 注意是数组
jquery:["jquery"],
loadsh:["loadsh"]
},
output:{
path:__dirname+"/src/dll",
filename:"./[name].js",
// library引用名:和app.js中
// import jq from "jquery"
// 和from 后面的名字有关
library:"[name]"
},
plugins:[
new webpack.DllPlugin({
path:__dirname+"/src/dll/[name].json",
name:"[name]"
})
]
}
然后
webpack --config webpack.dll.js
按照webpack.dll.js打包后会在src中多一个文件夹dll:
dll
| - jquery.js
| - jquery.json
| - loadsh.js
| - loadsh.json
然后就可以webpack回车打包了,因为有了之前的dll文件夹中生成的文件,打包速度会明显加快
2.通过include减少loader范围
所有的loader的options配置中都有include配置项,可以划定这个loader的处理范围
在用vue-cli2构建的项目中build文件夹下是一些配置,在其中的webpack.base.config.js文件中找到对js问价的配置:
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
test文件夹一般是用在测试的时候。我们尽可能的缩小他的处理范围,甚至我们可以直接缩小到只关注我们的业务代码。
还可以看到其中用到了很多resolve,但是resolve需要消耗拼接和路径查找时间的,所以我们可以用相对路径或者简单的字符串的拼接能完成的路径,就不要走resolve。(和第五点有关)
但是用resolve还是方便一点???
3.HappyPack
作用是让loader可以并行处理,用多线程来处理。
以处理js为例:
在用vue-cli2构建的项目中build文件夹下是一些配置,在其中的webpack.base.config.js文件中作如下配置:
{
test: /\.js$/,
// 将原来的babel-loader改变
// id值是根据在生产配置中
// 定义的happypack插件来的
loader: 'happypack/loader?id=happyBabel',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
在其中的webpack.prod.config.js文件中添加如下配置:
//需要自己下载
const HappyPack=require('happypack');
//os是node自带的不用下载
//作用是获取此电脑的系统信息
//因为要根据我们的cpu数量
//来新建happypack线程池
const os=require('os');
const happyThreadPoll=HappyPack.TreadPool({size:os.cpus().length})
//size就是设置开几条线程
//一般是根据操作系统cpu数量来开
使用中报错:
TypeError: HappyPack.TreadPool is not a function
然后我把全局安装的webpack降低到3.12.0版本,(每次打包,命令行都有显示使用的webpack的版本,发现无论是否本地安装了不同版本的webpack,他都是用的全局webpack打包的)。。。试了一圈解决了,都是不知道为什么,可能是字母写错了。
在开启了多线程之后,速度加快了,而且你第二次执行打包,因为有第一次的缓存,所以速度会比第一次快。
但是要注意:如果某个loader处理的文件很少,就可以不用happypack,因为使用happypack操作也是要花费时间的,所以可能得不偿失。
建议用happypack代替babel-loader就可以了,因为并行处理某些文件可能会出错。
4.Uglify优化
在webpack4中已经废除,但是在webpack3中可以使用,例如在vue-cli2构建的项目的webpack.prod.config.js中,可以在原本的uglyfyjs的配置中加上:
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
//注意加上下面两项,处理文件多时效果明显
parallel: true,
cache:true
}),
5.减少resolve,sourcemap,cache-loader,用新版本的node和webpack
cache-loader是专门拿来缓存的loader,但是现在来说作用不大,在webpack3的版本中还是有用的,在4版本中webpack自己就会缓存loader的处理结果。
在webpack3中:
npm install cache-loader --save
比如你要缓存图片的处理结果,就在所有处理图片的loader之前加上这个loader
长缓存优化
长缓存就是浏览器会缓存js等文件,第二次就是从缓存中取出这个js。所以js文件的内容和名字没有改变的话,它是不会拉取新的文件的。
每一次打包都会是不同的hash值(但是在同一次打包中,所有打包文件名后面的hash都是相同的)。我们通常是不会改第三方模块,所以打包出的vendor.js就可以利用长缓存,所以我们希望vendor.js文件后面的hash值不要变化。
有两种不同的场景:
- 把hash改为chunkhash
这一种场景就是我们改变了我们的业务代码(改变了app.js),我们就把hash改为chunkhash:
output: {
path: __dirname + "/dist",
// filename: "./[name].[hash].js",
filename: "./[name].[chunkhash].js",
publicPath: "./"
},
这样,hash就只和chunk内容有关了,在一次打包中每个文件名后面的hash都是不一样的,但是同一个文件多次打包的名字相同。这样就可以保证浏览器更新更少的资源。
- NameChunksPlugin和NamedModulesPlugin
使用场景:比如在app.js中,我们改变了一些模块的引入顺序也增加了一些新的模块,这样的话每个文件的chunkid就会改变,这样就会导致两次打包的文件名的hash发生改变,
在webpack.config.js注册插件的地方注册:
这样就能保证hash的不变了。