Add caching to popular builds and buil stats Closes #1308

This commit is contained in:
Kalle
2023-03-12 14:17:43 +02:00
parent f8f4f3665f
commit 6a585cff5a
8 changed files with 144 additions and 53 deletions

View File

@@ -71,3 +71,6 @@ export const LOHI_TOKEN_HEADER_NAME = "Lohi-Token";
export const CUSTOMIZED_CSS_VARS_NAME = "css";
export const MAX_AP = 57;
export const ONE_HOUR_IN_MS = 60 * 60 * 1000;
export const TWELVE_HOURS_IN_MS = 12 * ONE_HOUR_IN_MS;

View File

@@ -45,7 +45,6 @@ const handleBotRequest = (
void i18Instance(request, remixContext).then((i18n) => {
const { pipe, abort } = renderToPipeableStream(
<I18nextProvider i18n={i18n}>
{/* @ts-expect-error TODO: fix since probably a real issue not just types? https://github.com/remix-run/remix/issues/5073#issuecomment-1380380695 */}
<RemixServer context={remixContext} url={request.url} />
</I18nextProvider>,
{
@@ -90,7 +89,6 @@ const handleBrowserRequest = (
void i18Instance(request, remixContext).then((i18n) => {
const { pipe, abort } = renderToPipeableStream(
<I18nextProvider i18n={i18n}>
{/* @ts-expect-error TODO: fix */}
<RemixServer context={remixContext} url={request.url} />
</I18nextProvider>,
{

View File

@@ -1,5 +1,6 @@
import type { LoaderArgs, MetaFunction, SerializeFrom } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { cachified } from "cachified";
import clsx from "clsx";
import { Ability } from "~/components/Ability";
import { Main } from "~/components/Main";
@@ -16,6 +17,8 @@ import {
} from "~/utils/urls";
import { popularBuilds } from "../build-stats-utils";
import { abilitiesByWeaponId } from "../queries/abilitiesByWeaponId.server";
import { cache } from "~/utils/cache.server";
import { ONE_HOUR_IN_MS, TWELVE_HOURS_IN_MS } from "~/constants";
export const meta: MetaFunction = (args) => {
const data = args.data as SerializeFrom<typeof loader> | null;
@@ -58,12 +61,22 @@ export const loader = async ({ params, request }: LoaderArgs) => {
const t = await i18next.getFixedT(request, ["builds", "weapons", "common"]);
const slug = params["slug"];
const weaponId = notFoundIfFalsy(weaponNameSlugToId(slug));
const abilities = abilitiesByWeaponId(weaponId);
const weaponName = t(`weapons:MAIN_${weaponId}`);
const cachedPopularBuilds = await cachified({
key: `popular-builds-${weaponId}`,
cache,
ttl: ONE_HOUR_IN_MS,
staleWhileRevalidate: TWELVE_HOURS_IN_MS,
// eslint-disable-next-line @typescript-eslint/require-await
async getFreshValue() {
return popularBuilds(abilitiesByWeaponId(weaponId));
},
});
return {
popularBuilds: popularBuilds(abilities),
popularBuilds: cachedPopularBuilds,
meta: {
weaponId,
slug: slug!,

View File

@@ -14,7 +14,7 @@ import styles from "../build-stats.css";
import { WeaponImage } from "~/components/Image";
import type { SendouRouteHandle } from "~/utils/remix";
import { notFoundIfFalsy } from "~/utils/remix";
import { MAX_AP } from "~/constants";
import { MAX_AP, ONE_HOUR_IN_MS, TWELVE_HOURS_IN_MS } from "~/constants";
import { useTranslation } from "~/hooks/useTranslation";
import {
BUILDS_PAGE,
@@ -24,6 +24,8 @@ import {
} from "~/utils/urls";
import { i18next } from "~/modules/i18n";
import { makeTitle } from "~/utils/strings";
import { cache } from "~/utils/cache.server";
import { cachified } from "cachified";
export const meta: MetaFunction = (args) => {
const data = args.data as SerializeFrom<typeof loader> | null;
@@ -72,11 +74,22 @@ export const loader = async ({ params, request }: LoaderArgs) => {
const weaponName = t(`weapons:MAIN_${weaponId}`);
const cachedStats = await cachified({
key: `build-stats-${weaponId}`,
cache,
ttl: ONE_HOUR_IN_MS,
staleWhileRevalidate: TWELVE_HOURS_IN_MS,
// eslint-disable-next-line @typescript-eslint/require-await
async getFreshValue() {
return abilityPointCountsToAverages({
allAbilities: averageAbilityPoints(),
weaponAbilities: averageAbilityPoints(weaponId),
});
},
});
return {
stats: abilityPointCountsToAverages({
allAbilities: averageAbilityPoints(),
weaponAbilities: averageAbilityPoints(weaponId),
}),
stats: cachedStats,
weaponId,
meta: {
slug: params["slug"]!,

12
app/utils/cache.server.ts Normal file
View File

@@ -0,0 +1,12 @@
import type { CacheEntry } from "cachified";
import LRUCache from "lru-cache";
declare global {
// This preserves the LRU cache during development
// eslint-disable-next-line
var __lruCache: LRUCache<string, CacheEntry<unknown>> | undefined;
}
export const cache = (global.__lruCache = global.__lruCache
? global.__lruCache
: new LRUCache<string, CacheEntry<unknown>>({ max: 5000 }));

View File

@@ -52,7 +52,7 @@ test.describe("User page", () => {
window.getComputedStyle(element).getPropertyValue("--bg").trim()
);
await expect(bodyColor()).resolves.toMatch("#ebebf0");
await expect(bodyColor()).resolves.toMatch(/#ebebf0/);
await goToEditPage(page);
@@ -61,7 +61,7 @@ test.describe("User page", () => {
// got redirected
await expect(page).not.toHaveURL(/edit/);
await expect(bodyColor()).resolves.toMatch("#4a412a");
await expect(bodyColor()).resolves.toMatch(/#4a412a/);
});
test("has redirecting custom url", async ({ page }) => {

132
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "3.0.0",
"dependencies": {
"@faker-js/faker": "^7.6.0",
"@headlessui/react": "^1.7.13",
"@headlessui/react": "1.7.10",
"@popperjs/core": "^2.11.6",
"@remix-run/node": "^1.14.1",
"@remix-run/react": "^1.14.1",
@@ -17,6 +17,7 @@
"@tldraw/tldraw": "^1.28.0",
"aws-sdk": "^2.1333.0",
"better-sqlite3": "^8.2.0",
"cachified": "^3.1.0",
"clsx": "^1.2.1",
"compressorjs": "^1.2.1",
"countries-list": "^2.6.1",
@@ -32,6 +33,7 @@
"just-clone": "^6.2.0",
"just-random-integer": "^4.2.0",
"just-shuffle": "^4.2.0",
"lru-cache": "7.18.3",
"markdown-to-jsx": "^7.1.9",
"nanoid": "~3.3.4",
"node-cron": "3.0.2",
@@ -2207,9 +2209,9 @@
"license": "MIT"
},
"node_modules/@headlessui/react": {
"version": "1.7.13",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.13.tgz",
"integrity": "sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==",
"version": "1.7.10",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.10.tgz",
"integrity": "sha512-1m66h/5eayTEZVT2PI13/2PG3EVC7a9XalmUtVSC8X76pcyKYMuyX1XAL2RUtCr8WhoMa/KrDEyoeU5v+kSQOw==",
"dependencies": {
"client-only": "^0.0.1"
},
@@ -3307,14 +3309,6 @@
"@esbuild/win32-x64": "0.16.3"
}
},
"node_modules/@remix-run/dev/node_modules/lru-cache": {
"version": "7.14.1",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/@remix-run/dev/node_modules/prettier": {
"version": "2.7.1",
"dev": true,
@@ -5032,6 +5026,18 @@
"node": ">= 10"
}
},
"node_modules/cacache/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cacheable-lookup": {
"version": "5.0.4",
"dev": true,
@@ -5080,6 +5086,11 @@
"once": "^1.3.1"
}
},
"node_modules/cachified": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cachified/-/cachified-3.1.0.tgz",
"integrity": "sha512-5yyRHcGF2DY+ZQ8zVw+Ge3rTHI+EbPXsrE1ZybQ2P8Nh/hqQLDPz/89j/ZuFggRy0aDLYPhuQ/QdTFtHgd/2Xw=="
},
"node_modules/call-bind": {
"version": "1.0.2",
"license": "MIT",
@@ -9147,13 +9158,11 @@
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"license": "ISC",
"dependencies": {
"yallist": "^4.0.0"
},
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"engines": {
"node": ">=10"
"node": ">=12"
}
},
"node_modules/lz-string": {
@@ -12085,13 +12094,6 @@
"react-i18next": "^11.13.0"
}
},
"node_modules/remix-i18next/node_modules/lru-cache": {
"version": "7.13.1",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/require-from-string": {
"version": "2.0.2",
"dev": true,
@@ -12367,6 +12369,17 @@
"node": ">=10"
}
},
"node_modules/semver/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
@@ -13160,6 +13173,18 @@
"node": ">=0.10.0"
}
},
"node_modules/stylelint/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/stylelint/node_modules/meow": {
"version": "9.0.0",
"dev": true,
@@ -15871,9 +15896,9 @@
"dev": true
},
"@headlessui/react": {
"version": "1.7.13",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.13.tgz",
"integrity": "sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==",
"version": "1.7.10",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.10.tgz",
"integrity": "sha512-1m66h/5eayTEZVT2PI13/2PG3EVC7a9XalmUtVSC8X76pcyKYMuyX1XAL2RUtCr8WhoMa/KrDEyoeU5v+kSQOw==",
"requires": {
"client-only": "^0.0.1"
}
@@ -16625,10 +16650,6 @@
"@esbuild/win32-x64": "0.16.3"
}
},
"lru-cache": {
"version": "7.14.1",
"dev": true
},
"prettier": {
"version": "2.7.1",
"dev": true
@@ -17810,6 +17831,17 @@
"ssri": "^8.0.1",
"tar": "^6.0.2",
"unique-filename": "^1.1.1"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"cacheable-lookup": {
@@ -17846,6 +17878,11 @@
}
}
},
"cachified": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cachified/-/cachified-3.1.0.tgz",
"integrity": "sha512-5yyRHcGF2DY+ZQ8zVw+Ge3rTHI+EbPXsrE1ZybQ2P8Nh/hqQLDPz/89j/ZuFggRy0aDLYPhuQ/QdTFtHgd/2Xw=="
},
"call-bind": {
"version": "1.0.2",
"requires": {
@@ -20413,10 +20450,9 @@
"dev": true
},
"lru-cache": {
"version": "6.0.0",
"requires": {
"yallist": "^4.0.0"
}
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="
},
"lz-string": {
"version": "1.4.4",
@@ -22173,11 +22209,6 @@
"intl-parse-accept-language": "^1.0.0",
"lru-cache": "^7.10.0",
"use-consistent-value": "^1.0.0"
},
"dependencies": {
"lru-cache": {
"version": "7.13.1"
}
}
},
"require-from-string": {
@@ -22341,6 +22372,16 @@
"version": "7.3.7",
"requires": {
"lru-cache": "^6.0.0"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"send": {
@@ -22822,6 +22863,15 @@
"version": "5.0.0",
"dev": true
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"meow": {
"version": "9.0.0",
"dev": true,

View File

@@ -34,7 +34,7 @@
},
"dependencies": {
"@faker-js/faker": "^7.6.0",
"@headlessui/react": "^1.7.13",
"@headlessui/react": "1.7.10",
"@popperjs/core": "^2.11.6",
"@remix-run/node": "^1.14.1",
"@remix-run/react": "^1.14.1",
@@ -42,6 +42,7 @@
"@tldraw/tldraw": "^1.28.0",
"aws-sdk": "^2.1333.0",
"better-sqlite3": "^8.2.0",
"cachified": "^3.1.0",
"clsx": "^1.2.1",
"compressorjs": "^1.2.1",
"countries-list": "^2.6.1",
@@ -57,6 +58,7 @@
"just-clone": "^6.2.0",
"just-random-integer": "^4.2.0",
"just-shuffle": "^4.2.0",
"lru-cache": "7.18.3",
"markdown-to-jsx": "^7.1.9",
"nanoid": "~3.3.4",
"node-cron": "3.0.2",