Open jiangjiu opened 6 years ago
文章写的很赞。TL;DR
部分第三点是不是写错了,应该是用 NamedChunksPlugin
插件来稳定 chunk的 id吧?另外真实场景是 NamedChunksPlugin
和 HashedModuleIdsPlugin
是一起用的吗?
文章写的很赞。
TL;DR
部分第三点是不是写错了,应该是用NamedChunksPlugin
插件来稳定 chunk的 id吧?另外真实场景是NamedChunksPlugin
和HashedModuleIdsPlugin
是一起用的吗?
感谢指正。 在我们的业务线上,这两个是一起使用的。
楼主,你的demo还在吗,我在异步加载时配置了NamedChunksPlugin还是全部生成了一遍,想看下你的demo
(设置optimization.moduleIds:'hash'可以达到同样的效果,不过需要webapck@4.16.0以上)
这里应该为 moduleIds: 'hashed',最靠谱的官方文档
楼主,看了您的文章受益匪浅,非常感谢。
但是我对你的
6. 增加异步模块
这里有点疑问,使用HashedModuleIdsPlugin已经把chunk id给稳定住了,就不再需要NamedChunksPlugin了吧,我尝试下,发现没有NamedChunksPlugin效果是一样的(Version: webpack 4.35.2 )。
我查看(文档)[https://webpack.docschina.org/guides/caching/#%E6%A8%A1%E5%9D%97%E6%A0%87%E8%AF%86%E7%AC%A6-module-identifier-],也是说这两个插件的功能是相同的。
楼主,看了您的文章受益匪浅,非常感谢。 但是我对你的
6. 增加异步模块
这里有点疑问,使用HashedModuleIdsPlugin已经把chunk id给稳定住了,就不再需要NamedChunksPlugin了吧,我尝试下,发现没有NamedChunksPlugin效果是一样的(Version: webpack 4.35.2 )。 我查看(文档)[https://webpack.docschina.org/guides/caching/#%E6%A8%A1%E5%9D%97%E6%A0%87%E8%AF%86%E7%AC%A6-module-identifier-],也是说这两个插件的功能是相同的。
在webpack4.3时,异步模块是没有chunk Name的,所以会使用数字自增。 我看文档里只是说明了同步模块,你试试异步模块会不会有问题?
楼主,看了您的文章受益匪浅,非常感谢。 但是我对你的
6. 增加异步模块
这里有点疑问,使用HashedModuleIdsPlugin已经把chunk id给稳定住了,就不再需要NamedChunksPlugin了吧,我尝试下,发现没有NamedChunksPlugin效果是一样的(Version: webpack 4.35.2 )。 我查看(文档)[https://webpack.docschina.org/guides/caching/#%E6%A8%A1%E5%9D%97%E6%A0%87%E8%AF%86%E7%AC%A6-module-identifier-],也是说这两个插件的功能是相同的。在webpack4.3时,异步模块是没有chunk Name的,所以会使用数字自增。 我看文档里只是说明了同步模块,你试试异步模块会不会有问题?
您好,我尝试下异步模块,确实会有这个问题,必须需要加入NamedChunksPlugin去解决,但是我现在的困惑更多了,NamedChunksPlugin和HashedModuleIdsPlugin有什么区别,为什么文档上写着只采用一个即可,这里说的不同mode下开启不同plugin,这些plugin没找到文档呢?
楼主,看了您的文章受益匪浅,非常感谢。 但是我对你的
6. 增加异步模块
这里有点疑问,使用HashedModuleIdsPlugin已经把chunk id给稳定住了,就不再需要NamedChunksPlugin了吧,我尝试下,发现没有NamedChunksPlugin效果是一样的(Version: webpack 4.35.2 )。 我查看(文档)[https://webpack.docschina.org/guides/caching/#%E6%A8%A1%E5%9D%97%E6%A0%87%E8%AF%86%E7%AC%A6-module-identifier-],也是说这两个插件的功能是相同的。在webpack4.3时,异步模块是没有chunk Name的,所以会使用数字自增。 我看文档里只是说明了同步模块,你试试异步模块会不会有问题?
您好,我尝试下异步模块,确实会有这个问题,必须需要加入NamedChunksPlugin去解决,但是我现在的困惑更多了,NamedChunksPlugin和HashedModuleIdsPlugin有什么区别,为什么文档上写着只采用一个即可,这里说的不同mode下开启不同plugin,这些plugin没找到文档呢?
webpack文档一直不算太好,而且内部机制过于复杂,个别稍微小众的plugin就需要去专门的github看issue和源码了。 多写demo测试,多翻翻源码,大概就可以整理一个思路出来了。
楼主,看了您的文章受益匪浅,非常感谢。 但是我对你的
6. 增加异步模块
这里有点疑问,使用HashedModuleIdsPlugin已经把chunk id给稳定住了,就不再需要NamedChunksPlugin了吧,我尝试下,发现没有NamedChunksPlugin效果是一样的(Version: webpack 4.35.2 )。 我查看(文档)[https://webpack.docschina.org/guides/caching/#%E6%A8%A1%E5%9D%97%E6%A0%87%E8%AF%86%E7%AC%A6-module-identifier-],也是说这两个插件的功能是相同的。在webpack4.3时,异步模块是没有chunk Name的,所以会使用数字自增。 我看文档里只是说明了同步模块,你试试异步模块会不会有问题?
您好,我尝试下异步模块,确实会有这个问题,必须需要加入NamedChunksPlugin去解决,但是我现在的困惑更多了,NamedChunksPlugin和HashedModuleIdsPlugin有什么区别,为什么文档上写着只采用一个即可,这里说的不同mode下开启不同plugin,这些plugin没找到文档呢?
webpack文档一直不算太好,而且内部机制过于复杂,个别稍微小众的plugin就需要去专门的github看issue和源码了。 多写demo测试,多翻翻源码,大概就可以整理一个思路出来了。
好的,谢谢~
基于webpack4[.3+]构建可预测的持久化缓存方案
web缓存的好处不用多说,自从webpack一桶江湖后,如何做Predictable long term caching with Webpack让配置工程师们头疼不已。
webpack4.3前,有相当多的文章介绍如何处理(见参考),这里想做些更到位的探索。
问题
当业务开发完成,准备上线时,问题就来了🤡:
不要放弃治疗🍷本文测试时候的一些版本:
TL;DR
contenthash
很爽很安逸🌈HashedModuleIdsPlugin
稳定moduleId。该插件会根据模块的相对路径生成一个四位数的hash作为模块id, 建议用于生产环境🎁NamedModuleIdsPlugin
稳定chunkId。需要长效缓存的资源
图片、字体等media资源 media资源可以使用
file-loader
根据资源内容生成hash值,配合url-loader
可以按需内联成base64格式,这里不多说。css css资源如果不做特殊处理,会直接打进js文件中;生产环境我们通常会使用
mini-css-extract-plugin
抽取到单独的文件中或是内联。js js文件的处理要麻烦的多,作为唯一的入口资源,js管理着其他module,引入了无穷无尽的疑问,这也是我们接下来的重点。
webpack4 hash类型
contenthash应该是一个比较重要的feature,webpack核心开发者认为这个可以完全替代chunkhash(见 issue#2096),也许会在webpack5中将contenthash改成
[hash]
。那么他们的区别在哪里呢?
简单来说,当chunk中包含css、wasm时,如果css有改动,chunkhash也会发生改变,导致chunk的哈希值变动;如果使用contenthash,css的改动不会影响chunk的哈希值,因为它是依据chunk 的js内容生成的。
知道有这么几种就够了,下面就从最基本的例子开始吧🚴♂️。
栗子们
接下来都会在
production mode
下测试(如果你不清楚webpack4新增的mode模式,去翻翻webpack mode 文档吧)。涉及到的拆包策略,会一笔带过,后续有时间再详细聊聊拆包相关的问题~
1. 简单的hash
最简单的配置文件如下👇,
入口文件
index.js
很简单:打包结果:
这个例子使用了
name + hash
进行文件命名,因为hash是根据module identifier
生成的,这意味着只要业务中有一点点小小的改动,hash值就会变,来看下面的例子。2. 增加一个vendors
让我们来增加一点点复杂性。
@灰大 在对Webpack的hash稳定性的初步探索中展示了一个有趣的例子,我们也来试试看。
现在我们给入口文件增加一个a.js模块:
a模块引入了lodash中的identity方法:
然后修改下webpack配置文件,以便抽出vendors文件及manifest。这里多说一句,runtimeChunk非常的小,同时可预见的并不会有体积上的大变,所以可以考虑内联进html。
打包结果是:
[hash] 的问题
相信你已经注意到了,上图打包后,所有的文件都具有相同的hash值,这意味着什么呢?
每一次业务迭代上线,用户端要重新接收静态资源,因为hash值每次都会变动,之前的一切缓存都失效了😬。
所以,我们想要做持久化缓存,肯定是不会用
[hash]
了。3. chunkhash了解一下?
在webpack4.3之前,我们只能选择chunkhash进行模块标识,然而这个玩意儿如不是很稳,配置工程师们废了九牛二虎之力用了各种黑科技才将hash值尽可能的稳定。
新出的contenthash和chunkhash有多大的区别呢😳?
来看下面几个例子。
使用chunkhash
我们将
[hash]
换成[chunkhash]
,看下打包结果:index、vendors和runtime都拥有了不同的哈希值,so far so good。
我们继续灰大的例子,在index.js中增加b.js模块,b模块只有一行代码:
打包结果:
index文件的哈希值变动符合预期,但是vendors的实质内容仍然是lodash包的identity方法,这个也变了就不能忍了。
原因是webpack4默认按照resolving order使用自增id进行模块标识,所以插入了b.js导致vendors的id错后了一个数,这一点我们diff一下两个vendors文件就可以看出,两个文件只有这里不同:
灰大文章中也提到了,解决方案很简单,使用
HashedModuleIdsPlugin
,这是一个内置插件,它会根据模块路径生成模块id,问题就迎刃而解了:(起初比较担心根据module path进行hash计算后命名,这样的方式是否会因操作系统不同而产生差异,毕竟已经吃过一次亏了,见windows/linux下path路径不一致的问题 ,好在webpack官方已经处理过这个问题了,无需操心了)
(设置
optimization.moduleIds:'hash'
可以达到同样的效果,不过需要webapck@4.16.0以上)打包结果:
4. 增加一个css 模块
入口文件增加c.css👇,c的内容不重要:
配置一下
mini-css-extract-plugin
将这个css模块抽取出来:然后打包。 改动一点c.css中的内容,再次打包。
这两次打包过程,我们只对c.css文件做了改动,预期是什么呢? 当然是希望只有css文件的哈希值有改动,然而事情并不符合预期:
注意看index.js的哈希值📌 打包后,入口文件的哈希值竟然也变了,这就很让人头疼了。
5. contenthash治愈一切?
contenthash并不能解决moduleId自增的问题
使用contenthash和chunkhash,在上述vendors文件的行为上,有什么样的区别呢? 能否解决因模块变动的问题?
答案是不能😅。 毕竟文件内容中包含了变动的东西,还是需要
HashedModuleIdsPlugin
插件。contenthash威力所在
contenthash可以解决的是,css模块修改后,js哈希值变动的问题。
修改配置文件👇:
直接来看对比:
可以看到,index.js的chunk 哈希值在改动前后是完全一致的💯。
6. 增加异步模块
为了优化首屏性能或是业务变得原来越臃肿时,我们不可避免的会进行一些异步模块的抽取和加载,通过dynamic import方式就很安逸。
然而,异步模块作为一个新的chunk,他的哈希值是啥样的嘞?
我们增加一个异步模块试试看。
async-module的内容也是不重要,重要的是增加这个模块前后的哈希值有了很大的变化! 没有异步模块:
增加异步模块:
再增加第二个异步模块:
上面的对比简直是一夜回到解放前。。。除了css文件的哈希值在线,其他的都发生了改变。
究其原因,是因为虽然我们稳定住了moduleId,但是对chunkId无能为力,而且异步的模块因为没有chunk.name,导致又使用了数字自增进行命名。
好在我们还有
NamedChunksPlugin
可以进行chunkId的稳定👇:除此之外还有其他的方式可以稳定chunkId,不过由于或多或少的缺点在这里就不赘述了,来看现在打包的结果:
可以看出,异步模块也都有了name值,同时vendors的哈希值也回归了。
7. 增加第二个入口文件
在业务迭代过程中,经常会增删一些页面,那么这样的场景,哈希值是如何变化的呢?
我们增加一个index2入口文件,内容是一句
console.log('i am index2~')
,来看打包结果:可以看到,除了增加了index2.js和runtime~index2.js这两个文件外,其余文件的哈希值都没有变动,完美😉
原因是我们已经稳定住了ChunkId,各个chunks不会再根据resolving order进行数字自增操作了。
在实际生产环境中,当新引入的chunk依赖了其他公用模块时,还是会导致一些文件的哈希值变动,不过这个可以通过拆包策略来解决,这里就不赘述了。
总结
本文通过一些例子,总结了通过webpack4做长效缓存的原理以及踩坑实践,而且这些已经运用在了我们的实际业务中,对于频繁迭代的业务来说,有相当大的性能提升。
webpack4的长效缓存相比之前的版本有了很大的进步,也有些许不足,但是相信这些在webapck5中都会得到解决🙆♀️~
参考