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

mfl*_*din 4 javascript caching reactjs remix.run

我需要从一个非常慢且很少变化的 API 获取数据,所以我想我应该使用内存缓存。我首先尝试了一种非常简单的方法,只需将其保存到路径中加载器函数范围之外的变量中:

let cache;

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

但这没有用。然后我尝试了一个适当的缓存库(lru-cache),但该缓存也始终是空的。然后我意识到整个文件在每个请求上都会重新加载,我猜这是开发模式的事情,所以我尝试将缓存的创建移动到一个单独的文件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;
Run Code Online (Sandbox Code Playgroud)

但该文件似乎也会根据每个请求重新加载。

如果我构建一个生产版本并运行一切都很好,但如果有某种方法让它在开发模式下工作也很好。

Kil*_*man 9

Remix 会清除require开发中每个请求的缓存以支持<LiveReload/>. 为了确保您的缓存在这些清除中幸存下来,您需要将其分配给global对象。

编辑:这是处理这个问题的更好方法

// utils/singleton.server.ts

// since the dev server re-requires the bundle, do some shenanigans to make
// certain things persist across that 
// Borrowed/modified from https://github.com/jenseng/abuse-the-platform/blob/2993a7e846c95ace693ce61626fa072174c8d9c7/app/utils/singleton.ts

export function singleton<Value>(name: string, value: () => Value): Value {
    const yolo = global as any
    yolo.__singletons ??= {}
    yolo.__singletons[name] ??= value()
    return yolo.__singletons[name]
}
Run Code Online (Sandbox Code Playgroud)
// utils/prisma.server.ts

import { PrismaClient } from '@prisma/client'
import { singleton } from './singleton.server.ts'

const prisma = singleton('prisma', () => new PrismaClient())
prisma.$connect()

export { prisma }
Run Code Online (Sandbox Code Playgroud)


sod*_*ind 6

作为Kilimans 回答的后续,我是这样做的:

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

declare global {
  var __cache: NodeCache | undefined;
}

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

export { cache };
Run Code Online (Sandbox Code Playgroud)

我在加载器中使用了它:

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, 60 * 60 * 24);
  return json(repos);
}
Run Code Online (Sandbox Code Playgroud)