简体   繁体   English

如何在 Remix.run 开发模式下使用内存缓存?

[英]How do I use in-memory cache in Remix.run dev mode?

I need to fetch data from an API that is pretty slow and seldom changes, so I thought I'd use an in-memory cache.我需要从速度很慢且很少更改的 API 中获取数据,所以我想我会使用内存缓存。 I first tried a very simple approach by just saving it to a variable outside the scope of the loader function in my route:我首先尝试了一种非常简单的方法,只需将其保存到我的路径中加载程序 function 的 scope 之外的变量中:

let cache;

export const loader = async () => {
  if (!cache) {
    // we always end up here
    cache = await (await fetch("...)).json()
  }
}

but that didn't work.但这没有用。 I then tried a proper caching library ( lru-cache ), but that cache was also always empty.然后我尝试了一个适当的缓存库( lru-cache ),但那个缓存也总是空的。 I then realized that the entired file got reloaded on each request which I guess is a dev mode thing, so I tried moving the creation of the cache to a separate file cache.server.ts and importing it from there.然后我意识到整个文件都会在每个请求上重新加载,我猜这是一个开发模式的事情,所以我尝试将缓存的创建移动到一个单独的文件cache.server.ts并从那里导入它。

import LRU from "lru-cache";
console.log("Creating cache"); // this is logged on each request
const cache = new LRU({ max: 200 });
export default cache;

But that file also seems to be reloaded on each request.但是该文件似乎也会在每次请求时重新加载。

If I build a production version and run that everything works great, but it would be nice to have some way of getting it to work in dev mode as well.如果我构建了一个生产版本并运行它,一切都很好,但如果能有某种方法让它在开发模式下也能工作,那就太好了。

Remix purges the require cache on every request in development to support <LiveReload/> . Remix 清除开发中每个请求的require缓存以支持<LiveReload/> To make sure your cache survives these purges, you need to assign it to the global object.为了确保您的缓存能够在这些清除中幸存下来,您需要将其分配给global对象。

Here's an example from the Jokes Tutorial这是笑话教程中的一个示例

import { PrismaClient } from "@prisma/client";

let db: PrismaClient;

declare global {
  var __db: PrismaClient | undefined;
}

// this is needed because in development we don't want to restart
// the server with every change, but we want to make sure we don't
// create a new connection to the DB with every change either.
if (process.env.NODE_ENV === "production") {
  db = new PrismaClient();
} else {
  if (!global.__db) {
    global.__db = new PrismaClient();
  }
  db = global.__db;
}

export { db };

https://remix.run/docs/en/v1/tutorials/jokes#connect-to-the-database https://remix.run/docs/en/v1/tutorials/jokes#connect-to-the-database

As a follow up on Kilimans answer, here's how I did it:作为对 Kilimans 回答的跟进,我是这样做的:

/*
 * @see https://www.npmjs.com/package/node-cache
 */
import NodeCache from "node-cache";
let cache: NodeCache;

declare global {
  var __cache: NodeCache | undefined;
}
const cacheSettings = {
  stdTTL: 60 * 60 * 24,
  checkperiod: 60 * 60 * 24,
};

if (process.env.NODE_ENV === "production") {
  cache = new NodeCache(cacheSettings);
} else {
  if (!global.__cache) {
    global.__cache = new NodeCache(cacheSettings);
  }
  cache = global.__cache;
}

export { cache };

And I used it in the loader:我在加载器中使用它:

import { getGitHubRepos } from "~/models/github.server";
import { cache } from "~/utils/cache";

export async function loader(args: LoaderArgs) {
  if (cache.has("GitHubRepos")) {
    return json(cache.get("GitHubRepos"));
  }
  const repos = await getGitHubRepos();
  cache.set("GitHubRepos", repos);
  return json(repos);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM