Replace lru-cache dep with light util

This commit is contained in:
Kalle 2026-06-12 21:46:59 +03:00
parent 6bfa2ce6e2
commit ffa12b05cb
6 changed files with 117 additions and 6 deletions

View File

@ -1,8 +1,8 @@
import clsx from "clsx";
import { LRUCache } from "lru-cache";
import * as React from "react";
import type { Tables } from "~/db/tables";
import { useHydrated } from "~/hooks/useHydrated";
import { LRUCache } from "~/modules/cache";
import { BLANK_IMAGE_URL, discordAvatarUrl } from "~/utils/urls";
import styles from "./Avatar.module.css";

67
app/modules/cache/index.test.ts vendored Normal file
View File

@ -0,0 +1,67 @@
import { describe, expect, it } from "vitest";
import { LRUCache } from "./index";
describe("LRUCache", () => {
it("stores and retrieves values", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
expect(cache.get("a")).toBe(1);
expect(cache.has("a")).toBe(true);
});
it("returns undefined for missing keys", () => {
const cache = new LRUCache<string, number>({ max: 2 });
expect(cache.get("missing")).toBeUndefined();
expect(cache.has("missing")).toBe(false);
});
it("evicts the least recently used entry once over capacity", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
cache.set("b", 2);
cache.set("c", 3);
expect(cache.has("a")).toBe(false);
expect(cache.get("b")).toBe(2);
expect(cache.get("c")).toBe(3);
});
it("counts reads as recent use", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
cache.set("b", 2);
cache.get("a");
cache.set("c", 3);
expect(cache.has("a")).toBe(true);
expect(cache.has("b")).toBe(false);
});
it("updates value without growing past capacity on re-set", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
cache.set("a", 2);
expect(cache.get("a")).toBe(2);
});
it("deletes a single entry", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
cache.delete("a");
expect(cache.has("a")).toBe(false);
});
it("clears all entries", () => {
const cache = new LRUCache<string, number>({ max: 2 });
cache.set("a", 1);
cache.set("b", 2);
cache.clear();
expect(cache.has("a")).toBe(false);
expect(cache.has("b")).toBe(false);
});
});

48
app/modules/cache/index.ts vendored Normal file
View File

@ -0,0 +1,48 @@
/**
* A lightweight least-recently-used cache backed by a `Map`. Once `max` entries
* are stored, inserting a new key evicts the least recently used one. Reading a
* key via `get` marks it as most recently used.
*/
export class LRUCache<K, V> {
private readonly max: number;
private readonly map = new Map<K, V>();
constructor({ max }: { max: number }) {
this.max = max;
}
get(key: K): V | undefined {
if (!this.map.has(key)) return undefined;
const value = this.map.get(key) as V;
this.map.delete(key);
this.map.set(key, value);
return value;
}
has(key: K): boolean {
return this.map.has(key);
}
set(key: K, value: V): void {
if (this.map.has(key)) {
this.map.delete(key);
}
this.map.set(key, value);
if (this.map.size > this.max) {
const oldest = this.map.keys().next().value as K;
this.map.delete(oldest);
}
}
delete(key: K): void {
this.map.delete(key);
}
clear(): void {
this.map.clear();
}
}

View File

@ -1,5 +1,5 @@
import type { CacheEntry } from "@epic-web/cachified";
import { LRUCache } from "lru-cache";
import { LRUCache } from "~/modules/cache";
declare global {
// This preserves the LRU cache during development

View File

@ -68,7 +68,6 @@
"isbot": "5.1.40",
"jsoncrush": "1.1.8",
"kysely": "0.29.0",
"lru-cache": "11.5.1",
"lucide-react": "1.17.0",
"markdown-to-jsx": "9.8.1",
"nanoid": "5.1.11",

View File

@ -102,9 +102,6 @@ importers:
kysely:
specifier: 0.29.0
version: 0.29.0(patch_hash=6f395b25414c1ef852485fa3a03d2d521816064697d8c4bff337e2b24d19daa6)
lru-cache:
specifier: 11.5.1
version: 11.5.1
lucide-react:
specifier: 1.17.0
version: 1.17.0(react@19.2.7)