Remix.run开发模式下如何实现可用的内存缓存?
开发模式服务端内存缓存失效解决方案
失效原因
缓存不生效是全栈框架开发模式的默认机制导致的:Remix、Next.js App Router这类框架的dev环境默认开启服务端模块热重载,每次请求触发热更新检测、模块重新求值时,模块作用域内声明的所有变量都会被重置——不管你是把缓存写在路由loader外层,还是抽成独立的cache.server.ts文件,只要模块被重载,之前存的缓存数据就会被清空。生产环境是一次性构建后启动服务,模块只会在服务启动时加载一次,所以缓存逻辑可以正常运行。
推荐方案:挂载缓存实例到Node全局对象
零依赖、不影响现有热更新开发体验,只需要把缓存实例挂载到Node进程级的globalThis对象上即可,这个对象不会随模块重载被重置,修改你的cache.server.ts代码如下:
import LRU from "lru-cache"; // TS类型声明,避免类型报错 declare global { var __projectLevelCache: LRU<string, unknown> | undefined; } // 全局对象上已有缓存实例就直接复用,没有就新建 const cache = globalThis.__projectLevelCache ?? new LRU({ max: 200, // 可按需求加TTL配置,比如缓存1小时 ttl: 1000 * 60 * 60 }); // 首次初始化时把实例挂到全局,后续模块重载不会重复执行初始化 if (!globalThis.__projectLevelCache) { globalThis.__projectLevelCache = cache; console.log("Cache instance initialized, will persist across dev hot reloads"); } export default cache;
注意:全局挂载的变量名建议加项目专属前缀,避免和其他依赖注入的全局变量冲突。
其他可选方案
- 关闭开发模式的服务端热重载:可以在框架配置文件中关闭server HMR、服务端按需重编译的特性,让dev环境和生产环境一样只在启动时加载一次模块,但代价是修改服务端代码后不会自动生效,每次改动需要手动重启服务,会大幅降低开发效率,不推荐使用。
- 本地文件/SQLite兜底缓存:如果不想用全局变量,可以把缓存数据写入本地临时文件、或者单文件SQLite实例,这类磁盘存储的数据不会随模块重载丢失,缺点是读写性能比内存缓存差,适合缓存数据量较大的场景。
提示:上述所有内存缓存方案仅适用于单实例服务部署场景,如果后续做多实例分布式部署,需要替换为Redis这类独立的分布式缓存服务,否则多实例间缓存不互通,依然会出现重复请求上游API的问题。
内容的提问来源于stack exchange,提问作者mflodin
相关产品推荐
相关产品推荐

