编程界常见的两大“换”:【用时间换空间】与【用空间换时间】。
用时间换空间,常见于网络通信时对传输内容的编码和压缩,通过发送端花费计算时间编码、压缩和接收端花费计算时间解码、解压缩,减少传输内容体积,从而达到整体效率最优。
用空间换时间,常见于把需要较长I/O时间或者昂贵计算才能得到的资源或者计算结果进行缓存,当下次使用时可以直接使用缓存,花费存储空间来节约时间,提高处理速度。
在Webpack的编译过程中,就可以通过对编译结果进行缓存而提升构建效率。
之所以聊到这个话题,是因为最近工作中碰到了一个问题:我需要配置less-loader的modifyVars选项来修改ant-design的样式类前缀,结果配置完了后在本地dev时死活都不生效。排查过后发现,是因为项目内 cache-loader 的编译缓存导致的浏览器拿到的样式内容仍然是旧的。删掉缓存后重新启动devServer就解决问题了。
先声明一点,以下讲到的内容均以Webpack 4为例;而Webpack 5已经内建了编译缓存的能力,并且 cache-loader 已弃用。
在Webpack中,主要对 js 和 css 的编译结果进行缓存:
- babel-loader 已经集成了编译缓存能力
- 样式处理中,可自行添加 cache-loader 处理
那么 cache-loader 和 babel-loader 是怎么如何判断应该命中缓存,还是应该重新编译并更新缓存呢?
cache-loader
缓存文件名称中的hash值是判断是否命中的重要标志,cache-loader 计算hash值的过程及其相关数据来源为:
从图中可看出,hash值是由3个要素确定:
- 当前 cache-loader 的版本号
- process.env.NODE_ENV
- request字符串
看到这里读者或许会疑问:在修改less文件后,cache-loader 是如何知道应该更新缓存的呢?
实际上,cache-loader 会在loader链执行的 pitch阶段 检查所要编译的目标文件的mtime,即文件的最近修改时间;而之前的缓存文件中保存了上次编译时目标文件的mtime,将两个mtime进行对比即可知是否需要重新编译了。
因此上面提到的修改 less-loader 的 modifyVars 后,拿到的样式仍然来自旧缓存的原因是:
- antd的less文件没有改动,因此其文件的mtime未变
- 缓存文件名的hash值也未变
babel-loader
babel-loader 生成缓存文件时,文件名中hash值的计算过程,在 babel-loader/lib/cache.js
的 filename()
中:
const filename = function (source, identifier, options) {
const hash = crypto.createHash("md4");
const contents = JSON.stringify({
source,
options,
identifier
});
hash.update(contents);
return hash.digest("hex") + ".json";
};
计算hash的三个要素为:
- source:编译目标的源代码字符串
- options:babel的编译选项,例如编译目标的文件路径、插件集合plugins、所用预设presets等
- identifier:一个对象的序列化值,具体如下
identifier = JSON.stringify({
options, // 跟上面的options是同一个对象,即babel的编译选项
"@babel/core": transform.version, // 所调用babel的版本号
"@babel/loader": version // 当前babel-loader的版本号
})
综合上面来看,babel-loader在计算缓存hash时涉及到了编译目标的源码、编译选项、所用babel的版本、当前babel-loader的版本等要素,覆盖面还是比较全的,能够保证当修改了代码、改变了编译选项时能够重新触发编译。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!