mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2026-10-15 11:15:45 -04:00
fix: add cacheLife("max") to build-time cached functions and clarify throw-vs-catch caching rule
- Add `cacheLife("max")` to `getLocalImage` (OG image) and `getStaticRoutes` (sitemap) so entries are held as long as possible during prerender instead of expiring at the default TTL
- Update AGENTS.md to distinguish build-time reads (catch inside the cached function, return a fallback, use a short `cacheLife` on the error path) from request-time reads (may throw from the cached function since they never run during prerender)
- Expand the `getCachedComments` comment to explain why throwing is only safe there: a throw inside `"use cache"` during prerender fails the build even if the caller catches it
This commit is contained in:
4 files changed
+7
-2
No files matched your search
@@ -137,7 +137,7 @@ export const createComment = async (data: {
|
||||
- Schema in `lib/db/schema.ts`; migrations are generated into `drizzle/` with `pnpm db:generate` and applied with `pnpm db:migrate`. Drizzle ORM is a pinned `1.0.0-rc` prerelease, so check its docs for v1 APIs (e.g. `defineRelations`).
|
||||
- `cacheComponents` is enabled. Cache expensive or remote reads with `"use cache"` and an explicit `cacheLife(...)` (add `cacheTag(...)` when something needs to invalidate it). Examples: `app/projects/github.ts`, `components/third-party/tweet.tsx`.
|
||||
- Use `"use cache: remote"` for reads that run at request time (inside a dynamic hole, e.g. after `headers()`/`connection()`) so the entry is shared across server instances; plain `"use cache"` is fine for anything that ends up in a prerendered shell. Example: `lib/data/comments.ts`.
|
||||
- Don't catch-and-return-a-fallback inside a cached function, or the failure gets cached; let it throw and catch in an uncached wrapper.
|
||||
- A throw inside a `"use cache"` function fails the build if it happens during prerender, even when a caller catches it. For data read at build time (`app/projects/github.ts`, `lib/data/stats.ts`), catch inside the cached function and return a fallback; to avoid pinning a failure for long, call a shorter `cacheLife()` on the failure path (see `components/third-party/tweet.tsx`). Only request-time reads (`lib/data/comments.ts`) may throw from the cached function and catch in an uncached wrapper, which keeps errors out of the cache entirely.
|
||||
- After mutations, call `updateTag()` (server actions) or `revalidateTag()` (route handlers), and only expire tags that some `cacheTag()` actually sets.
|
||||
|
||||
```typescript
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { cacheLife } from "next/cache";
|
||||
import { notFound } from "next/navigation";
|
||||
import { ImageResponse } from "next/og";
|
||||
|
||||
@@ -31,6 +32,7 @@ const loadGoogleFont = async (font: string, weight: number): Promise<ArrayBuffer
|
||||
|
||||
const getLocalImage = async (src: string): Promise<ArrayBuffer | string> => {
|
||||
"use cache";
|
||||
cacheLife("max");
|
||||
|
||||
// https://stackoverflow.com/questions/5775469/whats-the-valid-way-to-include-an-image-with-no-src/14115340#14115340
|
||||
const NO_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import path from "node:path";
|
||||
|
||||
import type { MetadataRoute } from "next";
|
||||
import { cacheLife } from "next/cache";
|
||||
import { glob } from "tinyglobby";
|
||||
|
||||
import { getFrontMatter } from "@/lib/posts";
|
||||
|
||||
const getStaticRoutes = async (): Promise<string[]> => {
|
||||
"use cache";
|
||||
cacheLife("max");
|
||||
|
||||
return glob("**/page.{tsx,mdx}", {
|
||||
cwd: path.join(process.cwd(), "app"),
|
||||
|
||||
@@ -17,7 +17,8 @@ export const commentsTag = (pageSlug: string) => `comments-${pageSlug}`;
|
||||
|
||||
/**
|
||||
* Shared across server instances since it's read at request time (inside dynamic holes), not at prerender. Throws on
|
||||
* failure so an error is never cached.
|
||||
* failure so an error is never cached -- only safe because it never runs during prerender, where a throw inside
|
||||
* "use cache" fails the build even if caught.
|
||||
*/
|
||||
const getCachedComments = async (pageSlug: string): Promise<CommentWithUser[]> => {
|
||||
"use cache: remote";
|
||||
|
||||
Reference in new issue
Block a user