您现在的位置是:亿华云 > 应用开发
Webpack5 持久化缓存实践
亿华云2025-10-08 18:50:58【应用开发】8人已围观
简介背景公司的云his静态项目代码量巨大,依赖的npm包大概有100个,打包一次大概要14分钟自研的hammer工具的本地打包虽然能提升部署时间,但是依赖开发的手动操作用来存放本地构建产物的服务器容量满了
背景
公司的久化云his静态项目代码量巨大,依赖的缓存npm包大概有100个,打包一次大概要14分钟
自研的实践hammer工具的本地打包虽然能提升部署时间,但是久化依赖开发的手动操作
用来存放本地构建产物的服务器容量满了,所以为了正常使用本地打包功能,缓存还得定期去清理服务器上的实践老文件,不够方便
解决思路
node版本提升 8.x -> 12.x
利用webpack5的久化持久化缓存提升构建效率
速度大幅度提升,快了7倍。缓存
使用基于rust开发的实践swc替代babel,测试的久化构建速度提升一分钟半左右,因生态不成熟,缓存不能上生产。实践
关键代码
module.exports = {
...
cache: {
// 将缓存类型设置为文件系统,久化默认是memory
type: filesystem,
buildDependencies: {
// 更改配置文件时,重新缓存
config: [__filename]
}
},缓存
optimization: {
// 值为"single"会创建一个在所有生成chunk之间共享的运行时文件
runtimeChunk: single,
moduleIds: deterministic,
},
}
webpack 在入口 chunk 中,包含了某些 boilerplate(引导模板),实践特别是 runtime 和 manifest。这些代码如果不被单独抽离会导致即使没有代码改动,打包出来的文件名仍然会改变,导致无法命中缓存。云服务器webpack4中使用HashedModuleIdsPlugin来生成hash值作为模块id,在webpack5中已经不需要了,moduleIds: deterministic,是用来保证模块的id不会随着解析顺序的变化而变化,生产环境默认开启。
缓存的方式(从构建层面来讲)
webpack V4
cache-loader:建议在开销较大的loader前加,比如babel-loader、vue-loader等;dll:对不经常改变版本的依赖(react、lodash),单独生成动态链接库(bundle),提高构建速度,需要DllPlugin 、DllReferencePlugin 搭配使用,通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 __webpack_require__ 函数来 require 他们,推荐在开发模式下使用webpack V5
文件系统缓存,配置方式见上面的关键代码,作用是将Webpack运行时存在于内存中的那些缓存,不是loader的源码库产物,更不是dll,根据Webpack运行环境的不同,在dev开发时依旧使用MemoryCachePlugin,而在build时使用IdleFileCachePlugin。dev/build的二次编译速度会远超cache-loader一些原理浅谈
Webpack 5令人期待的持久缓存优化了整个构建流程,原理依然还是那一套:当检测到某个文件变化时,根据依赖关系,只对依赖树上相关的文件进行编译,从而大幅提高了构建速度。官方经过测试,16000 个模块组成的单页应用,速度竟然可以提高 98%!其中值得注意的是持久缓存会将缓存存储到磁盘。
对于一个持续化构建过程来说,第一次构建是一次全量构建,然后它会将相关产物序列化缓存在磁盘中(serialize)。后续构建具体流程可以依赖于上一次的缓存进行:读取磁盘缓存 -> 校验模块 -> 解封模块内容。因为模块之间的关系并不会被显式缓存,因此模块之间的关系仍然需要在每次构建过程中被校验,这个校验过程和正常的 webpack 进行分析依赖关系时的亿华云逻辑是完全一致的。
对于 resolver 的缓存同样可以持久化缓存起来,一旦 resolver 缓存经过校验后发现准确匹配,就可以用于快速寻找依赖关系。如果 resolver 缓存校验失败的情况,将会直接执行 resolver 的常规构建逻辑。
缓存的安全性设计
unsafeCache在webpack 4.x的构建过程中基于timestamp比对策略的一种cache方式,它有两个维度,resolve(解析器)的unsafeCache和module(模块)的unsafeCache。如果同时开启,那么从入口文件开始,webpack通过resolve规则解析所有的依赖文件,将模块之间的依赖关系和解析后的文件内容保存起来,并存储依赖的最后变更时间(timestamp),一旦发现相同引用,返回缓存。
而webpack 5.x版本已经放弃了这种缓存策略,默认只针对开启cache选项并且是node_modules下的依赖才开启unsafeCache,判断是否有文件系统序列化后的文件信息来判断是否需要重新构建。
safeCache模块间的依赖关系被基于内容对比的算法(contentHash)被记录下来,并存入到ModulGraph的class中的weakmap,相比于依赖时间戳的方式更可靠。
缓存的容量限制
除了需要考虑缓存的安全性,缓存的容量限制也不能忽视,缓存不可能无限叠加,这里就涉及到经典的LRU cache算法(Least Recently Used 最近最少使用)。
当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。
LRU算法的改进方案redis使用的改进算法LIRS、LRU-K等,感兴趣的同学自行查阅
作者:丁楠。我不生产代码,我是代码的搬运工。
很赞哦!(87)
相关文章
- 第五步:重复第四步,直到找到正确的纪录。
- Go语言出现后,Java还是好选择吗?
- 消息中间件:谈一谈 RocketMQ 的技术架构
- Pandas的五项高级功能及使用方法
- 顶级域名可以增加企业品牌的价值。随着经济的快速发展,域名已不再是企业在网络中的独立地位。顶级域名的服务范围、企业产品、综合形象体现等,对于企业单位来说,顶级域名的重要性不言而喻。
- 永别了,Java的“小苹果”!
- Kubernetes vs.Docker:了解容器和编排
- 为什么0.1+0.2不等于0.3?原来编程语言是这么算的……
- 2. 不要花大价钱买域名,新手鉴别能力不足,容易投资失误。
- 用 Python 分析招聘岗位,结果 Python 薪资竟然垫底。。。