简体   繁体   中英

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. I first tried a very simple approach by just saving it to a variable outside the scope of the loader function in my route:

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. 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.

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/> . To make sure your cache survives these purges, you need to assign it to the global object.

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

As a follow up on Kilimans answer, here's how I did it:

/*
 * @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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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