webpack性能优化 —— CommonsChunkPlugin
2017-09-10 15:21
1081 查看
前言:
相信大家对webpack并不陌生,用
webpack打包也是非常常见的事,但是
webpack在打包的时候有很多配置可以对打包就行优化。
最近正好在研究这方面的东西,所以在此记录一下,以便日后查看。
一、webpack-bundle-analyzer
在进入正文之前先说一个“好玩”的东西,是一个对webpack打包之后的文件进行分析的工具——webpack-bundle-analyzer1. 安装
虽然是在webpack的配置文件中使用,但并不是
webpack官方提供的插件,需要使用
npm进行安装:
npm install webpack-bundle-analyzer --save-dev
2. 使用
首先在webpack的配置文件中引入
webpack-bundle-analyzer,比如我的文件名是
webpack.demo.config.js:
// webpack.demo.config.js var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
接着使用引入的
BundleAnalyzerPlugin:
// webpack.demo.config.js new BundleAnalyzerPlugin({ analyzerMode: 'server', analyzerHost: '127.0.0.1', analyzerPort: 8888, reportFilename: 'report.html', defaultSizes: 'parsed', openAnalyzer: true, generateStatsFile: false, statsFilename: 'stats.json', statsOptions: null, logLevel: 'info' })
可以看到里面的参数还是很多的:
analyzerMode:表示已什么方式查看分析结果,可选参数为
server,
staticor
disabled。
analyzerHost:
analyzerMode为
server的时候生效,表示启动http服务的IP地址。
analyzerPort:
analyzerMode为
server的时候生效,表示启动http服务的端口号。
reportFilename:
analyzerMode为
static的时候生效,表示输出静态文件的文件名,输出路径
output路径相同。
defaultSizes:表示默认显示的数据模式,可选参数为
stat,
parsedor
gzip。
openAnalyzer:
true|false,表示是否在打包完成之后自动打开分析界面。
generateStatsFile:
true|false,表示是否生成
.json文件。
statsFilename:设置
generateStatsFile为
true的时候生成的
.json文件名。
statsOptions:通过修改生成的
.json文件中的
source:false来排除模块的源码。
logLevel:日志的显示方式,可选参数为
info,
warn,
erroror
silent。
3. 效果
无论是通过http服务还是通过打开静态文件的方式效果都是一样的:从上面就可以看出上面的数据有三种,分别是
defaultSizes的三个参数,由于我设置的是
parsed所以默认显示
parsed的大小。
简单解释一下
defaultSizes三个参数的含义:
stat:是指打包之前的文件大小
parsed:是指打包之后的文件大小
gzip:是指通过
gzip压缩之后的文件大小
如果默认设置了
parsed,但是我想看
stat时候的文件大小视图改怎么办呢?
当然可以在这个分析界面中去调整:
4. 小结
把最近看到的好东西拿出来分享一下,觉得使用这个东西一眼就能看出打包后的结构,每个模块分的很清晰,而且通过视图中每个模块占的面积大小很直观的能看出各个文件的体积比例,这对打包的分析很有帮助,并且使用简单,不需要进行什么复杂的配置。二、CommonsChunkPlugin
接下来进入正题,就是这个webpack本身提供的插件 —— CommonsChunkPlugin首先,介绍一下插件的使用格式;
然后,分析其中的每个参数的作用;
最后,举一个实际的“栗子”。
1. 介绍
看到CommonsChunkPlugin这个名字,大概明白这个插件是跟公共模块有关系的。没错,这个插件就是用来提取出代码中公共的部分,并且将他们打包到一个单独的文件里面,这样就避免了重复打包。同时,由于配置中有
minChunks(在文章后面会讲这个参数的作用)这个参数的存在可以满足一些其他的需求,不仅仅是提取公共部分这么简单了,而且一个文件中可以使用多次
CommonsChunkPlugin插件。
另外,还需要知道两个名词:
chunk和
chunkName。
chunk:通过
CommonsChunkPlugin生成的一个文件就是一个chunk,由于可能多次使用插件,所以每次打完包可能会很多
chunk。
注:如果是多入口,每一个入口文件都是一个
chunk。
chunkName:上面说过每使用一次插件就会生成一个
chunk,那这些
chunk通过什么区分呢?答案就是
chunkName。
2. 使用
由于是webpack提供的插件,所以就不需要安装了,直接在配置文件中引入,同样在此还是以
webpack.demo.config.js为配置文件:
// webpack.demo.config.js var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin") /* * 省略其他代码 **/ new CommonsChunkPlugin({ name: string, // or names: string[], filename: string, minChunks: number|Infinity|function(module, count) -> boolean, chunks: string[], children: boolean, async: boolean|string, minSize: number, })
or
当然,你也可以选择在头部一次引入
webpack,以后内置的插件都可以通过
webpack来使用,像这样:
// webpack.demo.config.js var webpack = require('webpack') /* * 省略其他代码 **/ new webpack.optimize.CommonsChunkPlugin({ name: string, // or names: string[], filename: string, minChunks: number|Infinity|function(module, count) -> boolean, chunks: string[], children: boolean, async: boolean|string, minSize: number, })
3. 参数
name|names:这里的
name就是上面所说的
chunkName,如果包括过个
chunk,那么就使用
names,以数组的形式传入
chunkName,如:
names: ['vendor','utils']
filename:打包后的文件名,可以省略,如果省略默认文件名为
name的值。
minChunks:定义提取公共部分的规则。
个人觉得这个
minChunks是整个插件最屌的没有之一(自行忽略)。
如果值为数字,例:
minChunks:2,就说明提取文件中最少被引用2次的代码,
如果值为
Infinity,将会直接创建一个公共的
chunk,但是里面没有模块,
如果值为函数,将会提取出满足函数条件的代码,生成一个公共
chunk,所以可以在这里实现以下定制化的需求。函数会提供两个参数:
module和
count。
chunks:定义从哪些
chunk中提取公共模块,如果省略,默认为入口
chunk。
children:默认是
false,多个
chunk里面的模块可能会有相同的依赖关系,如果设置为
true,将其中相同的依赖提到父元素中(但是会影响初始加载的时间)。
async:异步加载的附加公共
chunk, 当下载附加组块时,它会并行自动下载。
minSize:创建公共
chunk之前,所有公共模块的的最小体积。
4. 实战
上面说了一堆理论,讲了一下基本结构,具体用法现在开始了!下面是我一个Vue工程的项目结构:
现在我想要提取出
node_modules中以
.js结尾的文件和
src下以
.vue结尾的文件,将他们分别打到两个文件中。
先看一下入口和出口文件:
entry: { main: './examples/main.js' }, output: { path: path.resolve(__dirname, '../demo'), filename: '[name].[chunkhash].js', }
接着,按照上面说的,我首先引入
CommonsChunkPlugin:
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin")
接着使用这个插件:
new CommonsChunkPlugin({ name: "list", minChunks: function (module, count) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), new CommonsChunkPlugin({ name: 'components', chunks: ['main'], minChunks: function (module, count) { return ( module.resource && /\.vue$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../src') ) === 0 ) } }), new CommonsChunkPlugin({ name: "manifest", chunks: ['list', 'components'] })
打完包之后的结果是这样的,确实单独打出了两个文件:
Asset Size Chunks Chunk Names components.8ec10c04b75e68ee707a.js 479 kB 1 [emitted] [big] components main.a33511b70c4ad0a4aead.js 738 kB 2 [emitted] [big] main list.b2de50f4150e217815ca.js 789 kB 3 [emitted] [big] list manifest.9412c3435bf535f63115.js 6.07 kB 4 [emitted] manifest
打包生成的文件目录结构是这样的:
用
webpack-bundle-analyzer打开效果是这样的:
5. 进阶
看着文档很简单,但是实际操作起来就有许多问题,比如:- 打包之后
Chunks那一列数字是什么?
- 出口文件中的
chunkhash是什么?
- 生成
manifest又是什么?
-
minChunks函数中的参数到底有什么作用?
chunkhash
首先,
chunkhash既然叫
hash,所以是一种
hash值。当然,你也可以这么定义出口文件:
filename: '[name].[hash].js'
这里解释一下chunkhash与hash的区别:
- 对于打包生成的每个文件都有单独的hash值,这个hash值就叫做chunkhash;
- 而如果我们用
[hash]定义出口文件,打包之后的文件hash值是一致的,因为这个hash是整个的hash值,我把出口文件改了之后打包生成的文件放在下面,可以跟上面打包后的文件对比一下;
- 所以,chunkhash与hash的区别就是私有hash与全局hash的关系。
Asset Size Chunks Chunk Names components.26ae71410d030a4f8f66.js 479 kB 1 [emitted] [big] components main.26ae71410d030a4f8f66.js 738 kB 2 [emitted] [big] main list.26ae71410d030a4f8f66.js 789 kB 3 [emitted] [big] list manifest.26ae71410d030a4f8f66.js 5.98 kB 4 [emitted] manifest
manifest
那么
manifest又是什么呢?其实就是
webpack的一个清单文件,
manifest的作用就是将你之前打包好的每个文件的
chunkhash利用
webpack的缓存机制保存起来,如果下次没有修给这个
chunk里面的文件,那你打包之后文件的
chunkhash是不变的,修改过的会生成新的
chunkhash。
接下来我修改上文中的其中一个
.vue文件,在重新打包的结果是这样的,可以跟之前的对比一下,看是不是其他
chunkhash没有变:
Asset Size Chunks Chunk Names components.c2315d7bc104f905405c.js 479 kB 1 [emitted] [big] components main.a33511b70c4ad0a4aead.js 738 kB 2 [emitted] [big] main list.b2de50f4150e217815ca.js 789 kB 3 [emitted] [big] list manifest.e3e56878b56c560148b7.js 6.07 kB 4 [emitted] manifest
minChunks
当
minChunks为函数的时候,
webpack会提供两个参数:
module和
count。其中,
module有两个属性
module.context和
module.resource:
-
module.resource:表示正在处理的文件位置(其实就是文件的路径)
-
module.context:表示文件所在的目录
-
count:表示文件被引用的次数
有兴趣可以把module.context和module.resource打印出来看一下。
对于
count的使用其实很简单,这里我还是想提一下,直接把官网的栗子拿过来说:
new CommonsChunkPlugin({ name: "list", minChunks: function (module, count) { // 这里就是说,将文件路径中存在somelib并且被引用了3次的文件 // 如果说没有前面的条件,完全可以直接设置minChunks:3 return module.resource && (/somelib/).test(module.resource) && count === 3 } }),
到这里,上面写的
CommonsChunkPlugin配置基本就很清晰了,但是对于打包之后的
Chunks列数字问题,我在这里说一下,那些数字其实叫做
Chunks.id,是自动生成的,从0开始。这时候细心的人发现我上面的打包结果中并没有0,是从1开始的,这是为什么呢?答案是:其实是有0的,只不过打出来的文件与本文并没有关系,所以让我手动把第一行给删了,不要纠结,就是从0开始的,没毛病。
6. 小节
上面就CommonsChunkPlugin的作用及配置进行了介绍,并且展示了一个小栗子,根据结果又分析出了很多东西。但是由于篇幅太长,配置里面的参数没有一一展示demo,如果想用可以自己再慢慢探索。
三、总结
到这里文章就结束了,主要的目的还是为了记录和学习,顺便分享一下,以上都是亲自实践以及一些个人的理解,有兴趣的话也可以互相交流,交流是人类进步的阶梯。相关文章推荐
- 基于CommonsChunkPlugin,webpack打包优化
- webpack 2.x 之 CommonsChunkPlugin
- webpack CommonsChunkPlugin详细教程
- webpack CommonsChunkPlugin详细教程
- webpack CommonsChunkPlugin 提取公共代码
- [Webpack 2] Grouping vendor files with the Webpack CommonsChunkPlugin
- 深入浅出的webpack构建工具---webpack3版本的CommonsChunkPlugin详解(六)
- Webpack CommonsChunkPlugin 理解
- webpack3最新版本配置研究(四) devtool,webpack-dev-server,CommonsChunkPlugin
- webpack.optimize.CommonsChunkPlugin插件的使用
- webpack的CommonsChunkPlugin插件
- [Webpack 2] Chunking common modules from multiple apps with the Webpack CommonsChunkPlugin
- 详解用webpack的CommonsChunkPlugin提取公共代码的3种方式
- webpack分离第三方库(CommonsChunkPlugin并不是分离第三方库的好办法DllPlugin科学利用浏览器缓存)
- webpack提取公共模块-CommonsChunkPlugin
- 用webpack的CommonsChunkPlugin提取公共代码的3种方式
- webpack CommonsChunkPlugin详细教程
- webpack CommonsChunkPlugin详细教程
- webpack中CommonsChunkPlugin详细教程(小结)
- Webpack CommonsChunk Plugin