perf: reuse locals.session from hook instead of re-awaiting locals.auth()

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.
This commit is contained in:
2026-04-23 15:06:05 +02:00
parent dfeeeb5fdf
commit 800a544190
14 changed files with 28 additions and 35 deletions
+2 -1
View File
@@ -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] 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] 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) - [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 - [ ] 6. Stream fitness stats loader — return promises for slow panels
- [ ] 7. Overview endpoint — add `.select(...)` projection, cap timeseries window - [ ] 7. Overview endpoint — add `.select(...)` projection, cap timeseries window
- [ ] 8. Calendar payload trim — drop `name` from `yearDays`, pre-filter `feastDots` server-side - [ ] 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/<part> 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?) [x] on /fitness/stats/histoy/<part> 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 [ ] Make the Period ended button a lot more prominent
[ ] swap heart emoji on recipe favorites to lucide icon [ ] swap heart emoji on recipe favorites to lucide icon
[ ] coop and migros cards on shopping list for scanning
## Refactor Recipe Search Component ## Refactor Recipe Search Component
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "homepage", "name": "homepage",
"version": "1.46.16", "version": "1.46.17",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+4 -4
View File
@@ -8,7 +8,7 @@ import type { Session } from '@auth/sveltekit';
type BriefRecipeWithFavorite = BriefRecipeType & { isFavorite: boolean }; type BriefRecipeWithFavorite = BriefRecipeType & { isFavorite: boolean };
export async function getUserFavorites(fetch: typeof globalThis.fetch, locals: App.Locals, recipeLang = 'rezepte'): Promise<string[]> { export async function getUserFavorites(fetch: typeof globalThis.fetch, locals: App.Locals, recipeLang = 'rezepte'): Promise<string[]> {
const session = await locals.auth(); const session = locals.session ?? await locals.auth();
if (!session?.user?.nickname) { if (!session?.user?.nickname) {
return []; return [];
@@ -47,10 +47,10 @@ export async function loadRecipesWithFavorites(
recipeLoader: () => Promise<BriefRecipeType[]>, recipeLoader: () => Promise<BriefRecipeType[]>,
recipeLang = 'rezepte' recipeLang = 'rezepte'
): Promise<{ recipes: BriefRecipeWithFavorite[], session: Session | null }> { ): 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(), recipeLoader(),
getUserFavorites(fetch, locals, recipeLang), getUserFavorites(fetch, locals, recipeLang)
locals.auth()
]); ]);
return { return {
@@ -36,7 +36,7 @@ export const load: PageServerLoad = async ({ params, url, locals, fetch }) => {
// Fetch angelus streak data for angelus/regina-caeli pages // Fetch angelus streak data for angelus/regina-caeli pages
if (angelusSlugs.has(params.prayer)) { if (angelusSlugs.has(params.prayer)) {
const session = await locals.auth(); const session = locals.session ?? await locals.auth();
if (session?.user?.nickname) { if (session?.user?.nickname) {
try { try {
const res = await fetch('/api/glaube/angelus-streak'); const res = await fetch('/api/glaube/angelus-streak');
@@ -43,7 +43,7 @@ function getMysteryForWeekday(date: Date, includeLuminous: boolean): string {
} }
export const load: PageServerLoad = async ({ url, fetch, locals, params }) => { 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) // Read toggle/mystery state from URL search params (for no-JS progressive enhancement)
const luminousParam = url.searchParams.get('luminous'); const luminousParam = url.searchParams.get('luminous');
@@ -4,12 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori
export const load: PageServerLoad = async ({ fetch, locals, params }) => { export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const apiBase = `/api/${params.recipeLang}`; const apiBase = `/api/${params.recipeLang}`;
const currentMonth = new Date().getMonth() + 1; 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] = await Promise.all([
const [res_all_brief, userFavorites, session] = await Promise.all([
fetch(`${apiBase}/items/all_brief`).then(r => r.json()), fetch(`${apiBase}/items/all_brief`).then(r => r.json()),
getUserFavorites(fetch, locals, params.recipeLang), getUserFavorites(fetch, locals, params.recipeLang)
locals.auth()
]); ]);
const all_brief = addFavoriteStatusToRecipes(res_all_brief, userFavorites); const all_brief = addFavoriteStatusToRecipes(res_all_brief, userFavorites);
@@ -19,8 +19,7 @@ export const load: PageServerLoad = async ({ fetch, params, locals, url }) => {
const strippedName = stripHtmlTags(item.name); const strippedName = stripHtmlTags(item.name);
const strippedDescription = stripHtmlTags(item.description); const strippedDescription = stripHtmlTags(item.description);
// Get session for user info const session = locals.session ?? await locals.auth();
const session = await locals.auth();
return { return {
item, item,
@@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori
export const load: PageServerLoad = async ({ fetch, locals, params }) => { export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const apiBase = `/api/${params.recipeLang}`; 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/category/${params.category}`),
fetch(`${apiBase}/items/all_brief`), fetch(`${apiBase}/items/all_brief`),
getUserFavorites(fetch, locals, params.recipeLang), getUserFavorites(fetch, locals, params.recipeLang)
locals.auth()
]); ]);
const [items, allRecipes] = await Promise.all([res.json(), allRes.json()]); const [items, allRecipes] = await Promise.all([res.json(), allRes.json()]);
@@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori
export const load: PageServerLoad = async ({ fetch, locals, params }) => { export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const apiBase = `/api/${params.recipeLang}`; 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/` + params.icon).then(r => r.json()),
fetch(`${apiBase}/items/icon`).then(r => r.json()), fetch(`${apiBase}/items/icon`).then(r => r.json()),
getUserFavorites(fetch, locals, params.recipeLang), getUserFavorites(fetch, locals, params.recipeLang)
locals.auth()
]); ]);
return { return {
@@ -8,11 +8,8 @@ export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const res_season = await fetch(`${apiBase}/items/in_season/` + current_month); const res_season = await fetch(`${apiBase}/items/in_season/` + current_month);
const item_season = await res_season.json(); const item_season = await res_season.json();
// Get user favorites and session const session = locals.session ?? await locals.auth();
const [userFavorites, session] = await Promise.all([ const userFavorites = await getUserFavorites(fetch, locals, params.recipeLang);
getUserFavorites(fetch, locals, params.recipeLang),
locals.auth()
]);
return { return {
season: addFavoriteStatusToRecipes(item_season, userFavorites), season: addFavoriteStatusToRecipes(item_season, userFavorites),
@@ -7,11 +7,8 @@ export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const res_season = await fetch(`${apiBase}/items/in_season/` + params.month); const res_season = await fetch(`${apiBase}/items/in_season/` + params.month);
const item_season = await res_season.json(); const item_season = await res_season.json();
// Get user favorites and session const session = locals.session ?? await locals.auth();
const [userFavorites, session] = await Promise.all([ const userFavorites = await getUserFavorites(fetch, locals, params.recipeLang);
getUserFavorites(fetch, locals, params.recipeLang),
locals.auth()
]);
return { return {
month: params.month, month: params.month,
@@ -4,11 +4,11 @@ import { getUserFavorites, addFavoriteStatusToRecipes } from "$lib/server/favori
export const load: PageServerLoad = async ({ fetch, locals, params }) => { export const load: PageServerLoad = async ({ fetch, locals, params }) => {
const apiBase = `/api/${params.recipeLang}`; 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/tag/${params.tag}`),
fetch(`${apiBase}/items/all_brief`), fetch(`${apiBase}/items/all_brief`),
getUserFavorites(fetch, locals, params.recipeLang), getUserFavorites(fetch, locals, params.recipeLang)
locals.auth()
]); ]);
const [items_tag, allRecipes] = await Promise.all([res_tag.json(), allRes.json()]); const [items_tag, allRecipes] = await Promise.all([res_tag.json(), allRes.json()]);
@@ -4,7 +4,7 @@ import { ToTryRecipe } from '$models/ToTryRecipe';
import { dbConnect } from '$utils/db'; import { dbConnect } from '$utils/db';
export const load: PageServerLoad = async ({ locals, params }) => { export const load: PageServerLoad = async ({ locals, params }) => {
const session = await locals.auth(); const session = locals.session ?? await locals.auth();
if (!session?.user) { if (!session?.user) {
const callbackUrl = encodeURIComponent(`/${params.recipeLang}/to-try`); const callbackUrl = encodeURIComponent(`/${params.recipeLang}/to-try`);
@@ -1,7 +1,7 @@
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch, locals }) => { 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([ const [res, goalRes, heatmapRes, nutritionRes, latestRes, periodRes, sharedRes] = await Promise.all([
fetch('/api/fitness/stats/overview'), fetch('/api/fitness/stats/overview'),
fetch('/api/fitness/goal'), fetch('/api/fitness/goal'),