Webpack长效缓存实践

前言

如何使Webpack生成稳定的Chunkid问题解决了,特来反哺社区

先总结一下。HashedModuleIdsPlugin用于稳定 ModuleId 的,我问的问题核心是 **生成稳
定的ChunkId**,这两者是不一样的。

问题描述

有人对Webpack比较了解的吗?

我这里有个问题想要请教一下:当我们新增模块(也就是entry加了新东西)的时候,怎么保证ChunkId保持稳定

比如我在entry下新增加了三个模块,但是带动了许多构建后的文件Hash也跟着变动,查看构建后的代码发现是因为ChunkId发生了递增导致的。项目已经配置了HashedModuleIdsPlugin,并且生效。

期望效果 : entry新增模块后,其他模块的构建后的文件Hash没有变化,提高缓存命中率。

下面是添加新模块并打包的前后文件Hash对比

添加新模块前后对比截图

《Webpack长效缓存实践》

《Webpack长效缓存实践》

《Webpack长效缓存实践》

《Webpack长效缓存实践》

如何生成稳定ModuleId

表现:

只修改了 home/index.js 的代码,但在最终的构建结果中,vendor.js 的文件指纹也被修改了

原因有两个:

  1. webpack runtime (运行时) 中包含 chunks ID 及其对应 chunkhash 的对象,但 runtime 被集成到 vendor.js 中。
  2. entry 内容修改后,由于 webpack 的依赖收集规则导致构建产生的 entry chunk 对应的 ID 发生变化,webpack runtime 也因此被改变。

解决办法:

  1. 使用CommonsChunkPlugin 继续将webpack runtime抽离出来
    《Webpack长效缓存实践》
  2. 使用HashedModuleIdsPlugin代替原有的ModuleId根据依赖的收集顺序递增的正整数生成规则。

顺便一提,生成稳定的ModuleId在官方文档 – 缓存中有提及

早前经过合理的配置(可以参考用 webpack 实现持久化缓存,实现了其他模块变动后,vendor.js的文件指纹不会发生变化的效果)

效果如下:

《Webpack长效缓存实践》

如何生成稳定的ChunkId

很多文章都只介绍到如何生成稳定的ModuleId,没有提到生成稳定的ChunkId

后来经过 @dahoshaw的提醒

可以看下Webpack的源码,Webpack是根据模块的顺序递增chunkid,源代码中的applyChunkIds函数,所以官方有提供NamedChunksPlugin插件来根据文件名来稳定你的chunkid

webpackJsonp有三个参数,每次有新的entry加入说明资源数增加了,Chunk数量也会跟着增加。ChunkId也会递增

这有点类似ModuleId递增变动导致的文件指纹变化而导致的长效缓存失效

他推荐的文章 Predictable long term caching with Webpack确实写的不错!

解决办法:

在生产环境中的Webpack配置添加plugin: NamedChunksPlugin

// 使用模块名称作为chunkid,替换掉原本的使用递增id来作为chunkid导致的[新增entry模块,其他模块的hash发生抖动,导致客户端长效缓存失效]
config.plugins.push(new webpack.NamedChunksPlugin((chunk) => {
  // 解决异步模块打包的问题
  if (chunk.name) {
    return chunk.name;
  }
  return chunk.modules.map(m => path.relative(m.context, m.request)).join("_");
}));

最后验证一下,我们先打包一下项目,打包结果结构如下:

dist
├── home
│   ├── haha.dc494f13ed558999751e.js
│   ├── index.2266d24e04004acaa5a6.css
│   └── index.2b15fbd2daa6c833f5d5.js
├── manifest.json
├── runtime.1de86da7006780a96879.js
├── static
│   └── images
│       ├── logo-ea7f33f9bddceac362c1d7f378043187.png
│       └── share-icon-881a5a400142ab60684b3cec860611b4.png
├── sub-home
│   ├── haha.141284e7095f605726ac.js
│   ├── index.7039775e1ba458814d14.js
│   └── index.efd6d51187ec8a058fe6.css
└── vendor.dee373a1cd36f461d200.js

4 directories, 11 files

假设我们打算新增sub-sub-home模块。新增这个模块后打包结果结构如下:

dist
├── home
│   ├── haha.dc494f13ed558999751e.js
│   ├── index.2266d24e04004acaa5a6.css
│   └── index.2b15fbd2daa6c833f5d5.js
├── manifest.json
├── runtime.1de86da7006780a96879.js
├── static
│   └── images
│       ├── logo-ea7f33f9bddceac362c1d7f378043187.png
│       └── share-icon-881a5a400142ab60684b3cec860611b4.png
├── sub-home
│   ├── haha.141284e7095f605726ac.js
│   ├── index.7039775e1ba458814d14.js
│   └── index.efd6d51187ec8a058fe6.css
├── sub-sub-home
│   ├── haha.6501ce2d3a138709282b.js
│   ├── index.c367ca84bd261f36f050.js
│   └── index.efd6d51187ec8a058fe6.css
└── vendor.dee373a1cd36f461d200.js

5 directories, 14 files

至此,通过Webpack实现长效缓存实践完美收官。

参考

项目演示地址

知乎 – webpack 每次打包公用vendor 每次hash都会变化,有办法解决吗?

用 webpack 实现持久化缓存

Predictable long term caching with Webpack

官方文档 – 缓存

    原文作者:John_Trump
    原文地址: https://segmentfault.com/a/1190000011550143
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞