如何在remix.run dev模式下使用内存中缓存?

发布于 2025-02-08 06:08:05 字数 669 浏览 2 评论 0原文

我需要从非常缓慢且很少更改的API中获取数据,因此我认为我会使用内存缓存。我首先尝试了一种非常简单的方法,只需将其保存到我路线上的加载器函数范围之外的变量:

let cache;

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

但这是不起作用的。然后,我尝试了一个适当的缓存库(lru-cache),但是该缓存也总是空的。然后,我意识到,我猜是一个dev模式的每个请求中重新加载了entired文件,因此我尝试将缓存的创建移至单独的文件 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;

但是该文件似乎也在每个请求上重新加载。

如果我构建生产版本并运行一切都很好,但是也很高兴能以某种方式使其在开发模式下工作。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

↙温凉少女 2025-02-15 06:08:05

混音清除需要在开发中的每个请求中缓存以支持< livereload/>。为了确保您的缓存能够存活这些清洗,您需要将其分配给global对象。

编辑:这是处理此此此操作的更好方法

// utils/singleton.server.ts

// since the dev server re-requires the bundle, do some shenanigans to make
// certain things persist across that

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.

EDIT: Here's a better way to handle this

// 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]
}
// 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 }
没有伤那来痛 2025-02-15 06:08:05

作为跟进乞力类人答案,这就是我的做法:

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

我在装载机中使用了它:

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);
}

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;
}

if (process.env.NODE_ENV === "production") {
  cache = new NodeCache();
} else {
  if (!global.__cache) {
    global.__cache = new NodeCache();
  }
  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, 60 * 60 * 24);
  return json(repos);
}
风为裳 2025-02-15 06:08:05

乞力马族的更新答案,这是我使用 micro-memoize with typescript:

import type memoize from "micro-memoize";
import { singleton } from "~/utils/singleton.server";
type Memoizer = typeof memoize;

const memoizer: Memoizer = singleton("memoize", () => require("micro-memoize"));
export { memoizer as memoize };

希望这可以帮助遇到相同问题的任何人,并且想使用比node-cache更现代的东西

再次感谢 kiliman 提供了更新的Singleton功能。

Following on from Kiliman's updated answer, here's how I did it using the micro-memoize package with TypeScript:

import type memoize from "micro-memoize";
import { singleton } from "~/utils/singleton.server";
type Memoizer = typeof memoize;

const memoizer: Memoizer = singleton("memoize", () => require("micro-memoize"));
export { memoizer as memoize };

Hopefully this helps anyone who's having the same issue and wants to use something more modern than node-cache.

Thanks again to Kiliman for providing the updated Singleton function.

丢了幸福的猪 2025-02-15 06:08:05

我也这样做是为了将其放在服务器端。制作具有以下内容的文件,并在您要在哪里使用它。

import NodeCache from 'node-cache';
let cache: NodeCache;

declare global {
  var __cache: NodeCache | undefined;
}

export default function getNodeCache() {
  if (process.env.NODE_ENV === 'production') {
    cache = new NodeCache();
  } else {
    if (!global.__cache) {
      global.__cache = new NodeCache();
    }
    cache = global.__cache;
  }

  return cache;
}

I did this to have it at the server side as well. Make a file with the following content and call it wherever you want to use it.

import NodeCache from 'node-cache';
let cache: NodeCache;

declare global {
  var __cache: NodeCache | undefined;
}

export default function getNodeCache() {
  if (process.env.NODE_ENV === 'production') {
    cache = new NodeCache();
  } else {
    if (!global.__cache) {
      global.__cache = new NodeCache();
    }
    cache = global.__cache;
  }

  return cache;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文