Webpack 构建提速实战:Cache-loader 使用详解与优化技巧
我的写法,亲测靠谱
Cache-loader 这个东西,我最早是在一个 Vue 项目里用上的。当时项目越来越大,每次改一行代码,Webpack 就得重新跑一遍 Babel、TS、Vue 模板编译,动不动就等十几秒。后来翻文档看到 cache-loader,想着试试看,结果一加就真香了——热更新从 12 秒降到 3 秒,开发体验直接拉满。
但别急着 copy 别人的配置,我一开始就是这么干的,结果踩了好几个坑。现在我一般这样写:
// webpack.config.js(简化版)
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /.js$/,
use: [
'cache-loader',
{
loader: 'babel-loader',
options: {
cacheDirectory: true // 这个也开,双重保险
}
}
],
include: path.resolve(__dirname, 'src')
},
{
test: /.vue$/,
use: [
'cache-loader',
'vue-loader'
]
}
]
}
};
关键点有几个:第一,cache-loader 必须放在最前面,因为 Webpack 的 loader 是从右往左执行的,你得先缓存后处理,不然缓存的是原始文件,没意义。第二,只对 src 目录生效,别把 node_modules 也包进去,不仅浪费空间,还可能因为依赖版本变化导致缓存污染。第三,Babel 自带的 cacheDirectory 也建议打开,和 cache-loader 不冲突,反而能互补。
缓存目录默认在 node_modules/.cache/cache-loader,不用管它,但如果你用的是 CI/CD,记得在构建前清掉缓存,不然可能因为环境差异导致奇怪的 bug。本地开发就完全不用管,让它自己跑就行。
这几种错误写法,别再踩坑了
我见过太多人把 cache-loader 用错,结果不但没提速,反而搞出一堆诡异问题。下面这几个反面案例,都是我或者同事亲手踩过的。
- 把 cache-loader 放在最后:比如写成
['babel-loader', 'cache-loader']。这等于用 Babel 处理完的代码再去缓存,但下次进来的时候,cache-loader 会直接返回缓存结果,跳过 Babel,那你的新代码根本没被编译!结果就是语法错误或者 undefined 变量满天飞。 - 全局开启,不加 include/exclude:有人图省事,直接给所有 .js 文件加 cache-loader,连 node_modules 里的都缓存。结果某次升级 lodash,缓存没失效,Webpack 还在用旧版本的代码,调试半天才发现是缓存惹的祸。所以一定要用
include: /src/锁定范围。 - 和 thread-loader 混用顺序错乱:有些项目为了提速,会同时用 thread-loader 和 cache-loader。正确的顺序应该是
['cache-loader', 'thread-loader', 'babel-loader']。如果写成['thread-loader', 'cache-loader', 'babel-loader'],那 cache-loader 其实缓存的是 thread-loader 的中间产物,而 thread-loader 本身是多线程的,序列化/反序列化成本高,反而拖慢速度。 - 在生产构建里用 cache-loader:千万别!cache-loader 是为开发环境设计的,目的是加速重复编译。生产构建本来就是一次性的,加它只会增加 I/O 开销,毫无收益。我之前接手一个项目,构建脚本里居然保留了 cache-loader,CI 跑得特别慢,删掉后快了 20%。
实际项目中的坑
除了配置顺序,还有些细节容易忽略。比如缓存键(cache key)的生成逻辑。cache-loader 默认会根据 loader 配置、文件内容、Webpack 版本等生成 hash。但如果你的 loader 配置里有函数或者动态值,比如:
{
loader: 'some-loader',
options: {
customFn: () => { /* ... */ }
}
}
那每次启动 Webpack,这个函数引用都会变,导致 cache key 不同,缓存永远失效。所以 options 里尽量只放纯对象或字符串。
另外,不要指望 cache-loader 能解决所有性能问题。它只对“重复编译相同文件”有效。如果你改的是公共组件,触发大量模块重新编译,那 cache-loader 帮不上忙,这时候得考虑 splitChunks 或者优化组件粒度。我之前有个页面,引入了 50 个图标组件,每次改一个图标,整个页面都要重编译,后来我把图标做成动态 import,配合 cache-loader,才真正稳住。
还有个小问题:cache-loader 在 Windows 上偶尔会因为路径大小写或者文件锁导致缓存写入失败。表现就是控制台报 EPERM 错误,但不影响构建。这种情况下,删掉 node_modules/.cache 重启就行,不算大问题,但得知道怎么回事,别慌。
最后提一句,Webpack 5 自带了持久化缓存(persistent caching),通过 cache: { type: 'filesystem' } 配置,效果比 cache-loader 更好,而且不用手动插 loader。如果你的项目已经升级到 Webpack 5,建议直接用内置缓存,别再折腾 cache-loader 了。不过很多老项目还在 Webpack 4,那就只能靠它续命。
结尾唠叨两句
以上是我这几年用 cache-loader 总结出来的一点经验,核心就一句话:**只在开发环境、只对源码、loader 顺序放对、别信万能药**。它确实能提升开发体验,但不是银弹。如果你的项目已经上 Webpack 5,赶紧切内置缓存;如果还在 Webpack 4,按我上面的写法配,基本不会出问题。
以上是我个人对 cache-loader 的完整讲解,有更优的实现方式欢迎评论区交流。这个技巧的拓展用法还有很多,后续会继续分享这类博客。

暂无评论