Move all sets to new static generation routine

This commit is contained in:
Sam Becker 2025-03-18 19:14:52 -05:00
parent f0d9ea28b6
commit c4b1e349e1
14 changed files with 131 additions and 83 deletions

View File

@ -13,6 +13,8 @@
"Consolas", "Consolas",
"CredentialsSignin", "CredentialsSignin",
"datetime", "datetime",
"depluralize",
"depluralizes",
"Eterna", "Eterna",
"exif", "exif",
"exifr", "exifr",

View File

@ -1,4 +1,4 @@
import { parameterize } from '@/utility/string'; import { parameterize, depluralize } from '@/utility/string';
describe('String', () => { describe('String', () => {
it('parameterizes', () => { it('parameterizes', () => {
@ -10,4 +10,11 @@ describe('String', () => {
expect(parameterize('"person\'s tag"')).toBe('persons-tag'); expect(parameterize('"person\'s tag"')).toBe('persons-tag');
expect(parameterize('宿宿宿宿')).toBe('宿宿宿宿'); expect(parameterize('宿宿宿宿')).toBe('宿宿宿宿');
}); });
it('depluralizes', () => {
expect(depluralize('lenses')).toBe('lens');
expect(depluralize('cameras')).toBe('camera');
expect(depluralize('tags')).toBe('tag');
expect(depluralize('recipes')).toBe('recipe');
expect(depluralize('films')).toBe('film');
});
}); });

View File

@ -9,20 +9,23 @@ import { FilmSimulation } from '@/simulation';
import { getIBMPlexMono } from '@/app/font'; import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { getUniqueFilmSimulations } from '@/photo/db/query'; import { getUniqueFilmSimulations } from '@/photo/db/query';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
export let generateStaticParams: export let generateStaticParams:
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined; (() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('films', 'image')) { if (shouldGenerateStaticParamsForCategory('films', 'image')) {
generateStaticParams = async () => { generateStaticParams = () =>
const simulations = await getUniqueFilmSimulations(); staticallyGenerateCategory(
return simulations 'films',
.map(({ simulation }) => ({ simulation })) 'image',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueFilmSimulations,
}; simulations => simulations.map(({ simulation }) => ({ simulation })),
);
} }
export async function GET( export async function GET(

View File

@ -7,8 +7,10 @@ import { Metadata } from 'next/types';
import { cache } from 'react'; import { cache } from 'react';
import { PATH_ROOT } from '@/app/paths'; import { PATH_ROOT } from '@/app/paths';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
const getPhotosFilmSimulationDataCachedCached = const getPhotosFilmSimulationDataCachedCached =
cache(getPhotosFilmSimulationDataCached); cache(getPhotosFilmSimulationDataCached);
@ -17,12 +19,13 @@ export let generateStaticParams:
(() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined; (() => Promise<{ simulation: FilmSimulation }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('films', 'page')) { if (shouldGenerateStaticParamsForCategory('films', 'page')) {
generateStaticParams = async () => { generateStaticParams = () =>
const simulations = await getUniqueFilmSimulations(); staticallyGenerateCategory(
return simulations 'films',
.map(({ simulation }) => ({ simulation })) 'page',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueFilmSimulations,
}; simulations => simulations.map(({ simulation }) => ({ simulation })),
);
} }
interface FilmSimulationProps { interface FilmSimulationProps {

View File

@ -9,20 +9,24 @@ import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import FocalLengthImageResponse from import FocalLengthImageResponse from
'@/image-response/FocalLengthImageResponse'; '@/image-response/FocalLengthImageResponse';
import { formatFocalLength, getFocalLengthFromString } from '@/focal'; import { formatFocalLength, getFocalLengthFromString } from '@/focal';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { getUniqueFocalLengths } from '@/photo/db/query'; import { getUniqueFocalLengths } from '@/photo/db/query';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
export let generateStaticParams: export let generateStaticParams:
(() => Promise<{ focal: string }[]>) | undefined = undefined; (() => Promise<{ focal: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'image')) { if (shouldGenerateStaticParamsForCategory('focal-lengths', 'image')) {
generateStaticParams = async () => { generateStaticParams = () =>
const focalLengths= await getUniqueFocalLengths(); staticallyGenerateCategory(
return focalLengths 'focal-lengths',
.map(({ focal }) => ({ focal: formatFocalLength(focal)! })) 'image',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueFocalLengths,
}; focalLengths => focalLengths
.map(({ focal }) => ({ focal: formatFocalLength(focal)! })),
);
} }
export async function GET( export async function GET(

View File

@ -7,8 +7,10 @@ import { PATH_ROOT } from '@/app/paths';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { cache } from 'react'; import { cache } from 'react';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
const getPhotosFocalDataCachedCached = cache((focal: number) => const getPhotosFocalDataCachedCached = cache((focal: number) =>
getPhotosFocalLengthDataCached({ getPhotosFocalLengthDataCached({
@ -20,12 +22,14 @@ export let generateStaticParams:
(() => Promise<{ focal: string }[]>) | undefined = undefined; (() => Promise<{ focal: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('focal-lengths', 'page')) { if (shouldGenerateStaticParamsForCategory('focal-lengths', 'page')) {
generateStaticParams = async () => { generateStaticParams = () =>
const focalLengths = await getUniqueFocalLengths(); staticallyGenerateCategory(
return focalLengths 'focal-lengths',
.map(({ focal }) => ({ focal: focal.toString() })) 'page',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueFocalLengths,
}; focalLengths => focalLengths
.map(({ focal }) => ({ focal: focal.toString() })),
);
} }
interface FocalLengthProps { interface FocalLengthProps {

View File

@ -6,7 +6,6 @@ import {
import { getIBMPlexMono } from '@/app/font'; import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { getUniqueLenses } from '@/photo/db/query'; import { getUniqueLenses } from '@/photo/db/query';
import { import {
getLensFromParams, getLensFromParams,
@ -15,17 +14,22 @@ import {
safelyGenerateLensStaticParams, safelyGenerateLensStaticParams,
} from '@/lens'; } from '@/lens';
import LensImageResponse from '@/image-response/LensImageResponse'; import LensImageResponse from '@/image-response/LensImageResponse';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
export let generateStaticParams: export let generateStaticParams:
(() => Promise<Lens[]>) | undefined = undefined; (() => Promise<Lens[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('lenses', 'image')) { if (shouldGenerateStaticParamsForCategory('lenses', 'image')) {
generateStaticParams = async () => { generateStaticParams = () =>
const lenses = await getUniqueLenses(); staticallyGenerateCategory(
return safelyGenerateLensStaticParams(lenses) 'lenses',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); 'image',
}; getUniqueLenses,
safelyGenerateLensStaticParams,
);
} }
export async function GET( export async function GET(

View File

@ -11,8 +11,10 @@ import {
LensProps, LensProps,
safelyGenerateLensStaticParams, safelyGenerateLensStaticParams,
} from '@/lens'; } from '@/lens';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; import {
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
const getPhotosLensDataCachedCached = cache(( const getPhotosLensDataCachedCached = cache((
make: string | undefined, make: string | undefined,
@ -27,11 +29,13 @@ export let generateStaticParams:
(() => Promise<Lens[]>) | undefined = undefined; (() => Promise<Lens[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('lenses', 'page')) { if (shouldGenerateStaticParamsForCategory('lenses', 'page')) {
generateStaticParams = async () => { generateStaticParams = () =>
const lenses = await getUniqueLenses(); staticallyGenerateCategory(
return safelyGenerateLensStaticParams(lenses) 'lenses',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); 'page',
}; getUniqueLenses,
safelyGenerateLensStaticParams,
);
} }
export async function generateMetadata({ export async function generateMetadata({

View File

@ -6,21 +6,24 @@ import {
import { getIBMPlexMono } from '@/app/font'; import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { getUniqueRecipes } from '@/photo/db/query'; import { getUniqueRecipes } from '@/photo/db/query';
import RecipeImageResponse from '@/image-response/RecipeImageResponse'; import RecipeImageResponse from '@/image-response/RecipeImageResponse';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
export let generateStaticParams: export let generateStaticParams:
(() => Promise<{ recipe: string }[]>) | undefined = undefined; (() => Promise<{ recipe: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('recipes', 'image')) { if (shouldGenerateStaticParamsForCategory('recipes', 'image')) {
generateStaticParams = async () => { generateStaticParams = () =>
const recipes = await getUniqueRecipes(); staticallyGenerateCategory(
return recipes 'recipes',
.map(({ recipe }) => ({ recipe })) 'image',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueRecipes,
}; recipes => recipes.map(({ recipe }) => ({ recipe })),
);
} }
export async function GET( export async function GET(

View File

@ -7,8 +7,10 @@ import { cache } from 'react';
import { generateMetaForRecipe } from '@/recipe'; import { generateMetaForRecipe } from '@/recipe';
import RecipeOverview from '@/recipe/RecipeOverview'; import RecipeOverview from '@/recipe/RecipeOverview';
import { getPhotosRecipeDataCached } from '@/recipe/data'; import { getPhotosRecipeDataCached } from '@/recipe/data';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
const getPhotosRecipeDataCachedCached = cache(getPhotosRecipeDataCached); const getPhotosRecipeDataCachedCached = cache(getPhotosRecipeDataCached);
@ -16,12 +18,13 @@ export let generateStaticParams:
(() => Promise<{ recipe: string }[]>) | undefined = undefined; (() => Promise<{ recipe: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('recipes', 'page')) { if (shouldGenerateStaticParamsForCategory('recipes', 'page')) {
generateStaticParams = async () => { generateStaticParams = () =>
const recipes = await getUniqueRecipes(); staticallyGenerateCategory(
return recipes 'recipes',
.map(({ recipe }) => ({ recipe })) 'page',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueRecipes,
}; recipes => recipes.map(({ recipe }) => ({ recipe })),
);
} }
interface RecipeProps { interface RecipeProps {

View File

@ -7,20 +7,23 @@ import TagImageResponse from '@/image-response/TagImageResponse';
import { getIBMPlexMono } from '@/app/font'; import { getIBMPlexMono } from '@/app/font';
import { ImageResponse } from 'next/og'; import { ImageResponse } from 'next/og';
import { getImageResponseCacheControlHeaders } from '@/image-response/cache'; import { getImageResponseCacheControlHeaders } from '@/image-response/cache';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { getUniqueTags } from '@/photo/db/query'; import { getUniqueTags } from '@/photo/db/query';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
export let generateStaticParams: export let generateStaticParams:
(() => Promise<{ tag: string }[]>) | undefined = undefined; (() => Promise<{ tag: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('tags', 'image')) { if (shouldGenerateStaticParamsForCategory('tags', 'image')) {
generateStaticParams = async () => { generateStaticParams = () =>
const tags = await getUniqueTags(); staticallyGenerateCategory(
return tags 'tags',
.map(({ tag }) => ({ tag })) 'image',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueTags,
}; tags => tags.map(({ tag }) => ({ tag })),
);
} }
export async function GET( export async function GET(

View File

@ -7,8 +7,10 @@ import { getPhotosTagDataCached } from '@/tag/data';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { cache } from 'react'; import { cache } from 'react';
import { shouldGenerateStaticParamsForCategory } from '@/category/server'; import {
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; shouldGenerateStaticParamsForCategory,
staticallyGenerateCategory,
} from '@/category/server';
const getPhotosTagDataCachedCached = cache((tag: string) => const getPhotosTagDataCachedCached = cache((tag: string) =>
getPhotosTagDataCached({ tag, limit: INFINITE_SCROLL_GRID_INITIAL})); getPhotosTagDataCached({ tag, limit: INFINITE_SCROLL_GRID_INITIAL}));
@ -17,12 +19,13 @@ export let generateStaticParams:
(() => Promise<{ tag: string }[]>) | undefined = undefined; (() => Promise<{ tag: string }[]>) | undefined = undefined;
if (shouldGenerateStaticParamsForCategory('tags', 'page')) { if (shouldGenerateStaticParamsForCategory('tags', 'page')) {
generateStaticParams = async () => { generateStaticParams = () =>
const tags = await getUniqueTags(); staticallyGenerateCategory(
return tags 'tags',
.map(({ tag }) => ({ tag })) 'page',
.slice(0, GENERATE_STATIC_PARAMS_LIMIT); getUniqueTags,
}; tags => tags.map(({ tag }) => ({ tag })),
);
} }
interface TagProps { interface TagProps {

View File

@ -7,7 +7,7 @@ import {
STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES, STATICALLY_OPTIMIZED_PHOTO_CATEGORY_OG_IMAGES,
} from '@/app/config'; } from '@/app/config';
import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db'; import { GENERATE_STATIC_PARAMS_LIMIT } from '@/photo/db';
import { pluralize } from '@/utility/string'; import { depluralize, pluralize } from '@/utility/string';
type StaticOutput = 'page' | 'image'; type StaticOutput = 'page' | 'image';
@ -30,9 +30,8 @@ export const staticallyGenerateCategory = async <T, K>(
const data = (await getData()).slice(0, GENERATE_STATIC_PARAMS_LIMIT); const data = (await getData()).slice(0, GENERATE_STATIC_PARAMS_LIMIT);
if (IS_BUILDING) { if (IS_BUILDING) {
console.log( const meta = pluralize(data.length, `${depluralize(key)} ${type}`);
`Statically generating ${key} (${pluralize(data.length, type)})`, console.log(`Statically generating ${meta}`);
);
} }
return formatData(data); return formatData(data);

View File

@ -47,6 +47,12 @@ export const pluralize = (
) => ) =>
`${count} ${count === 1 ? singular : plural ?? `${singular}s`}`; `${count} ${count === 1 ? singular : plural ?? `${singular}s`}`;
export const depluralize = (string: string) =>
// Handle plurals like "lenses"
/ses$/i.test(string)
? string.replace(/es$/i, '')
: string.replace(/s$/i, '');
export const formatCountDescriptive = ( export const formatCountDescriptive = (
count: number, count: number,
verb = 'found', verb = 'found',