Rspack 的缓存机制是如何工作的?
Rspack 的缓存机制是提升构建性能的核心手段。Rspack 目前支持内存缓存(Memory Cache)和持久化缓存(Persistent Cache)两种类型,配合快照策略、构建依赖追踪、可移植缓存等机制,能够在开发调试和生产构建中显著缩短耗时。
内存缓存
内存缓存是 Rspack 最基础的缓存形式,将模块编译结果和依赖图保存在内存中,使得增量构建和 HMR 能够快速响应。
在开发模式下,Rspack 默认启用内存缓存:
javascriptmodule.exports = { cache: true }
也可以显式指定类型:
javascriptmodule.exports = { cache: { type: 'memory' } }
内存缓存的特点是速度极快,但进程退出后缓存即丢失。对于日常开发中的热更新场景,内存缓存已经足够,这也是 Rspack 在 HMR 性能上表现优异的原因之一。
在生产模式下,cache 默认为 false,即不启用任何缓存。
持久化缓存
持久化缓存将构建结果写入磁盘,使得下次启动时可以直接复用上一次的编译产物,而无需重新执行模块解析和代码转换。这对于大型项目的冷启动场景尤为关键。
基本配置
javascriptconst path = require('path') module.exports = { cache: { type: 'persistent' } }
启用后,Rspack 默认将缓存存储在 node_modules/.cache/rspack 目录下。你也可以自定义存储位置:
javascriptmodule.exports = { cache: { type: 'persistent', storage: { type: 'filesystem', directory: path.resolve(__dirname, '.cache/rspack') } } }
构建依赖(buildDependencies)
buildDependencies 用于声明哪些文件的变更应当导致缓存失效。Rspack 会计算这些文件的哈希值,当哈希值发生变化时,持久化缓存自动失效。
javascriptmodule.exports = { cache: { type: 'persistent', buildDependencies: [__filename, path.join(__dirname, 'tsconfig.json')] } }
需要注意的是,与 webpack 不同,Rspack 默认不预设任何构建依赖项。如果你希望配置文件修改后缓存能正确失效,必须将配置文件路径加入 buildDependencies。
缓存版本(version)
version 字段用于隔离不同配置的缓存。不同 version 值的缓存互不干扰,Rspack 会为每个版本生成独立的缓存目录。
javascriptmodule.exports = { cache: { type: 'persistent', version: '1.0.0' } }
当项目配置发生重大变更(如升级 loader 版本、修改 babel 配置等)时,更新 version 可以避免旧缓存导致的构建错误。需要注意的是,不要在配置不同的构建之间共享相同的 version 和 storage.directory,否则可能命中错误的缓存。
缓存清理(maxGenerations)
Rspack 通过 maxGenerations 控制缓存的存活周期。默认值为 1,意味着如果某条缓存在下一次编译中没有被使用,就会被清理。增大该值可以让缓存存活更多轮次:
javascriptmodule.exports = { cache: { type: 'persistent', maxGenerations: 5 } }
此外,Rspack 在启动时会自动清理超过 7 天未被访问的缓存目录,无需手动维护。
快照策略(snapshot)
快照策略决定了 Rspack 如何判断文件是否在上次构建后被修改,直接影响缓存验证的效率。
managedPaths
managedPaths 用于指定由包管理器管理的目录(默认包含 node_modules)。对这些路径下的文件,Rspack 通过 package.json 中的 version 字段判断是否变更,而不是逐文件计算哈希,从而大幅加速缓存验证。
javascriptmodule.exports = { cache: { type: 'persistent', snapshot: { managedPaths: [/node_modules/] } } }
immutablePaths
immutablePaths 用于指定内容不会变更的路径。一旦路径被标记为不可变,Rspack 在热重启时会跳过对这些文件的检查,直接认为缓存有效:
javascriptmodule.exports = { cache: { type: 'persistent', snapshot: { immutablePaths: [path.join(__dirname, 'dist')] } } }
unmanagedPaths
unmanagedPaths 用于排除不应被 managedPaths 规则覆盖的路径。如果你的 node_modules 中有通过 git submodule 等方式管理的包,可以将其加入此列表,让 Rspack 对这些文件采用更精确的哈希验证。
可移植缓存(portable)
可移植缓存是 Rspack 为 CI/CD 场景设计的能力。启用后,缓存序列化时会将绝对路径转换为相对路径,使得缓存可以在不同机器和操作系统之间共享。
javascriptmodule.exports = { cache: { type: 'persistent', portable: true } }
典型的应用场景是在 CI 环境中:先将缓存构建并上传为 artifact,后续的构建任务直接下载复用,无需每次从零开始编译。Windows、Linux、macOS 之间可以共享同一份缓存,不需要为每个平台维护独立的缓存副本。
需要注意的是,可移植模式下,项目目录外的文件会被转换为相对路径,在新环境中如果这些文件不存在,可能触发额外的重新编译。
只读缓存(readonly)
只读模式适用于 CI 场景中使用预热缓存的构建任务。启用后,Rspack 只从磁盘读取缓存,不会写入新数据:
javascriptmodule.exports = { cache: { type: 'persistent', readonly: Boolean(process.env.CI) } }
这在多构建任务共享同一份缓存 artifact 时特别有用,可以避免并发写入导致的缓存损坏。
从 webpack 迁移缓存配置
如果你从 webpack 迁移到 Rspack,缓存配置需要做以下调整:
- 缓存类型:将
cache.type: 'filesystem'改为cache.type: 'persistent' - 构建依赖:将
buildDependencies从对象格式{ config: [__filename] }改为数组格式[__filename] - 缓存版本:将 webpack 的
cache.name和cache.version合并为 Rspack 的cache.version - 快照配置:将顶层的
snapshot配置移入cache.snapshot
javascript// webpack 配置 module.exports = { cache: { type: 'filesystem', buildDependencies: { config: [__filename] }, name: 'my-app', version: '1.0' } } // Rspack 配置 module.exports = { cache: { type: 'persistent', buildDependencies: [__filename], version: 'my-app-1.0' } }
实际使用建议
开发环境:默认启用内存缓存即可满足需求。如果项目较大导致冷启动慢,可以同时开启持久化缓存。
生产构建:生产模式下缓存默认关闭。对于频繁构建的场景(如预发布环境),可以开启持久化缓存并将 buildDependencies 配置完整,确保配置变更时缓存正确失效。
CI/CD 环境:结合 portable: true 和 readonly: true,将构建产物缓存作为 pipeline artifact 上传和复用,可以显著减少 CI 构建时间。根据社区反馈,命中缓存后构建速度可以提升 2-3 倍。
缓存失效排查:如果遇到缓存未命中或构建结果异常,首先检查 buildDependencies 是否完整,其次确认 version 是否需要更新。Rspack 在 cache.profile: true 开启时会输出缓存统计信息,有助于定位问题。