mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-25 04:26:00 -05:00
Add caching to popular builds and buil stats Closes #1308
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>,
|
||||
{
|
||||
|
||||
@@ -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!,
|
||||
|
||||
@@ -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
12
app/utils/cache.server.ts
Normal 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 }));
|
||||
@@ -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
132
package-lock.json
generated
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user