From 800a5441904cd25c3d10076966d71ddbd57aaacb Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Thu, 23 Apr 2026 15:06:05 +0200 Subject: [PATCH] perf: reuse locals.session from hook instead of re-awaiting locals.auth() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hooks.server.ts already awaits auth() once and stores the result on locals.session. In-scope loaders (recipe list + filter views, rosary, prayers, calendar — already done — and fitness stats) were awaiting locals.auth() a second time per request. Switched to the existing `locals.session ?? await locals.auth()` pattern so the hook's result is reused. Also pulls session out of Promise.all legs since it's now synchronous when the hook ran. Scope: loaders only — actions, /admin, /edit, /add intentionally skipped. --- TODO.md | 3 ++- package.json | 2 +- src/lib/server/favorites.ts | 8 ++++---- .../[prayers=prayersLang]/[prayer]/+page.server.ts | 2 +- .../[rosary=rosaryLang]/+page.server.ts | 2 +- src/routes/[recipeLang=recipeLang]/+page.server.ts | 7 +++---- src/routes/[recipeLang=recipeLang]/[name]/+page.server.ts | 3 +-- .../category/[category]/+page.server.ts | 6 +++--- .../[recipeLang=recipeLang]/icon/[icon]/+page.server.ts | 6 +++--- src/routes/[recipeLang=recipeLang]/season/+page.server.ts | 7 ++----- .../season/[month]/+page.server.ts | 7 ++----- .../[recipeLang=recipeLang]/tag/[tag]/+page.server.ts | 6 +++--- src/routes/[recipeLang=recipeLang]/to-try/+page.server.ts | 2 +- src/routes/fitness/[stats=fitnessStats]/+page.server.ts | 2 +- 14 files changed, 28 insertions(+), 35 deletions(-) diff --git a/TODO.md b/TODO.md index 70b96590..29fec1d1 100644 --- a/TODO.md +++ b/TODO.md @@ -8,7 +8,7 @@ Order = impact. Font items + app.html preload intentionally skipped. - [x] 2. Chart.js dynamic import in `FitnessChart.svelte` (drop 244 KB from non-stats fitness routes) - [x] 3. Recipe API endpoints — drop `JSON.parse(JSON.stringify(...))` double-serialize (9 endpoints). Client-side shuffle / cache headers deferred (would require rethinking hero preload + hydration) - [x] 4. Favorites page — drop unnecessary `all_brief` fetch (verified Search uses `favoritesOnly` so `allRecipes` was redundant) -- [ ] 5. Replace redundant `locals.auth()` with `locals.session` across recipe/calendar/fitness loaders +- [x] 5. Replace redundant `locals.auth()` with `locals.session` across recipe/calendar/fitness loaders (loaders only; actions + admin/edit/add pages skipped) - [ ] 6. Stream fitness stats loader — return promises for slow panels - [ ] 7. Overview endpoint — add `.select(...)` projection, cap timeseries window - [ ] 8. Calendar payload trim — drop `name` from `yearDays`, pre-filter `feastDots` server-side @@ -26,6 +26,7 @@ Order = impact. Font items + app.html preload intentionally skipped. [x] on /fitness/stats/histoy/ for body measurement graphs, make the range reasonable. e.g., if we have 1 cm change, do not fill the entire y-height with 1 cm. Use reasonable padding for low ranges (i think we do something like htis already on the weight graph?) [ ] Make the Period ended button a lot more prominent [ ] swap heart emoji on recipe favorites to lucide icon +[ ] coop and migros cards on shopping list for scanning ## Refactor Recipe Search Component diff --git a/package.json b/package.json index 80afa286..6e212445 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.46.16", + "version": "1.46.17", "private": true, "type": "module", "scripts": { diff --git a/src/lib/server/favorites.ts b/src/lib/server/favorites.ts index db79d906..5ea07fe5 100644 --- a/src/lib/server/favorites.ts +++ b/src/lib/server/favorites.ts @@ -8,7 +8,7 @@ import type { Session } from '@auth/sveltekit'; type BriefRecipeWithFavorite = BriefRecipeType & { isFavorite: boolean }; export async function getUserFavorites(fetch: typeof globalThis.fetch, locals: App.Locals, recipeLang = 'rezepte'): Promise { - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); if (!session?.user?.nickname) { return []; @@ -47,10 +47,10 @@ export async function loadRecipesWithFavorites( recipeLoader: () => Promise, recipeLang = 'rezepte' ): Promise<{ recipes: BriefRecipeWithFavorite[], session: Session | null }> { - const [recipes, userFavorites, session] = await Promise.all([ + const session = locals.session ?? await locals.auth(); + const [recipes, userFavorites] = await Promise.all([ recipeLoader(), - getUserFavorites(fetch, locals, recipeLang), - locals.auth() + getUserFavorites(fetch, locals, recipeLang) ]); return { diff --git a/src/routes/[faithLang=faithLang]/[prayers=prayersLang]/[prayer]/+page.server.ts b/src/routes/[faithLang=faithLang]/[prayers=prayersLang]/[prayer]/+page.server.ts index 43d082f0..b00eb2a1 100644 --- a/src/routes/[faithLang=faithLang]/[prayers=prayersLang]/[prayer]/+page.server.ts +++ b/src/routes/[faithLang=faithLang]/[prayers=prayersLang]/[prayer]/+page.server.ts @@ -36,7 +36,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => { // Fetch angelus streak data for angelus/regina-caeli pages if (angelusSlugs.has(params.prayer)) { - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); if (session?.user?.nickname) { try { const res = await fetch('/api/glaube/angelus-streak'); diff --git a/src/routes/[faithLang=faithLang]/[rosary=rosaryLang]/+page.server.ts b/src/routes/[faithLang=faithLang]/[rosary=rosaryLang]/+page.server.ts index 482b9933..c1f3bc92 100644 --- a/src/routes/[faithLang=faithLang]/[rosary=rosaryLang]/+page.server.ts +++ b/src/routes/[faithLang=faithLang]/[rosary=rosaryLang]/+page.server.ts @@ -43,7 +43,7 @@ function getMysteryForWeekday(date: Date, includeLuminous: boolean): string { } export const load: PageServerLoad = async ({ url, fetch, locals, params }) => { - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); // Read toggle/mystery state from URL search params (for no-JS progressive enhancement) const luminousParam = url.searchParams.get('luminous'); diff --git a/src/routes/[recipeLang=recipeLang]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/+page.server.ts index bcd1931e..fd805532 100644 --- a/src/routes/[recipeLang=recipeLang]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/+page.server.ts @@ -4,12 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori export const load: PageServerLoad = async ({ fetch, locals, params }) => { const apiBase = `/api/${params.recipeLang}`; const currentMonth = new Date().getMonth() + 1; + const session = locals.session ?? await locals.auth(); - // Fetch all_brief, favorites, and session in parallel - const [res_all_brief, userFavorites, session] = await Promise.all([ + const [res_all_brief, userFavorites] = await Promise.all([ fetch(`${apiBase}/items/all_brief`).then(r => r.json()), - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() + getUserFavorites(fetch, locals, params.recipeLang) ]); const all_brief = addFavoriteStatusToRecipes(res_all_brief, userFavorites); diff --git a/src/routes/[recipeLang=recipeLang]/[name]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/[name]/+page.server.ts index bca66d13..9a1c8f98 100644 --- a/src/routes/[recipeLang=recipeLang]/[name]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/[name]/+page.server.ts @@ -19,8 +19,7 @@ export const load: PageServerLoad = async ({ fetch, params, locals, url }) => { const strippedName = stripHtmlTags(item.name); const strippedDescription = stripHtmlTags(item.description); - // Get session for user info - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); return { item, diff --git a/src/routes/[recipeLang=recipeLang]/category/[category]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/category/[category]/+page.server.ts index 3575608e..11b29d5c 100644 --- a/src/routes/[recipeLang=recipeLang]/category/[category]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/category/[category]/+page.server.ts @@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori export const load: PageServerLoad = async ({ fetch, locals, params }) => { const apiBase = `/api/${params.recipeLang}`; - const [res, allRes, userFavorites, session] = await Promise.all([ + const session = locals.session ?? await locals.auth(); + const [res, allRes, userFavorites] = await Promise.all([ fetch(`${apiBase}/items/category/${params.category}`), fetch(`${apiBase}/items/all_brief`), - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() + getUserFavorites(fetch, locals, params.recipeLang) ]); const [items, allRecipes] = await Promise.all([res.json(), allRes.json()]); diff --git a/src/routes/[recipeLang=recipeLang]/icon/[icon]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/icon/[icon]/+page.server.ts index ea7cc528..c2c37eeb 100644 --- a/src/routes/[recipeLang=recipeLang]/icon/[icon]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/icon/[icon]/+page.server.ts @@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori export const load: PageServerLoad = async ({ fetch, locals, params }) => { const apiBase = `/api/${params.recipeLang}`; - const [item_season, icons, userFavorites, session] = await Promise.all([ + const session = locals.session ?? await locals.auth(); + const [item_season, icons, userFavorites] = await Promise.all([ fetch(`${apiBase}/items/icon/` + params.icon).then(r => r.json()), fetch(`${apiBase}/items/icon`).then(r => r.json()), - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() + getUserFavorites(fetch, locals, params.recipeLang) ]); return { diff --git a/src/routes/[recipeLang=recipeLang]/season/+page.server.ts b/src/routes/[recipeLang=recipeLang]/season/+page.server.ts index c8bbfe8a..99e14170 100644 --- a/src/routes/[recipeLang=recipeLang]/season/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/season/+page.server.ts @@ -8,11 +8,8 @@ export const load: PageServerLoad = async ({ fetch, locals, params }) => { const res_season = await fetch(`${apiBase}/items/in_season/` + current_month); const item_season = await res_season.json(); - // Get user favorites and session - const [userFavorites, session] = await Promise.all([ - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() - ]); + const session = locals.session ?? await locals.auth(); + const userFavorites = await getUserFavorites(fetch, locals, params.recipeLang); return { season: addFavoriteStatusToRecipes(item_season, userFavorites), diff --git a/src/routes/[recipeLang=recipeLang]/season/[month]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/season/[month]/+page.server.ts index 3d96f2dd..25300a33 100644 --- a/src/routes/[recipeLang=recipeLang]/season/[month]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/season/[month]/+page.server.ts @@ -7,11 +7,8 @@ export const load: PageServerLoad = async ({ fetch, locals, params }) => { const res_season = await fetch(`${apiBase}/items/in_season/` + params.month); const item_season = await res_season.json(); - // Get user favorites and session - const [userFavorites, session] = await Promise.all([ - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() - ]); + const session = locals.session ?? await locals.auth(); + const userFavorites = await getUserFavorites(fetch, locals, params.recipeLang); return { month: params.month, diff --git a/src/routes/[recipeLang=recipeLang]/tag/[tag]/+page.server.ts b/src/routes/[recipeLang=recipeLang]/tag/[tag]/+page.server.ts index 6165c6c0..7317c4c4 100644 --- a/src/routes/[recipeLang=recipeLang]/tag/[tag]/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/tag/[tag]/+page.server.ts @@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori export const load: PageServerLoad = async ({ fetch, locals, params }) => { const apiBase = `/api/${params.recipeLang}`; - const [res_tag, allRes, userFavorites, session] = await Promise.all([ + const session = locals.session ?? await locals.auth(); + const [res_tag, allRes, userFavorites] = await Promise.all([ fetch(`${apiBase}/items/tag/${params.tag}`), fetch(`${apiBase}/items/all_brief`), - getUserFavorites(fetch, locals, params.recipeLang), - locals.auth() + getUserFavorites(fetch, locals, params.recipeLang) ]); const [items_tag, allRecipes] = await Promise.all([res_tag.json(), allRes.json()]); diff --git a/src/routes/[recipeLang=recipeLang]/to-try/+page.server.ts b/src/routes/[recipeLang=recipeLang]/to-try/+page.server.ts index f14cd625..f2fde10b 100644 --- a/src/routes/[recipeLang=recipeLang]/to-try/+page.server.ts +++ b/src/routes/[recipeLang=recipeLang]/to-try/+page.server.ts @@ -4,7 +4,7 @@ import { ToTryRecipe } from '$models/ToTryRecipe'; import { dbConnect } from '$utils/db'; export const load: PageServerLoad = async ({ locals, params }) => { - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); if (!session?.user) { const callbackUrl = encodeURIComponent(`/${params.recipeLang}/to-try`); diff --git a/src/routes/fitness/[stats=fitnessStats]/+page.server.ts b/src/routes/fitness/[stats=fitnessStats]/+page.server.ts index c753d722..e2330ca4 100644 --- a/src/routes/fitness/[stats=fitnessStats]/+page.server.ts +++ b/src/routes/fitness/[stats=fitnessStats]/+page.server.ts @@ -1,7 +1,7 @@ import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ fetch, locals }) => { - const session = await locals.auth(); + const session = locals.session ?? await locals.auth(); const [res, goalRes, heatmapRes, nutritionRes, latestRes, periodRes, sharedRes] = await Promise.all([ fetch('/api/fitness/stats/overview'), fetch('/api/fitness/goal'),