perf: fix slow page loads and gate performance in CI

- Ship one hashed Tailwind stylesheet instead of two (one render-blocking)
- Compress responses in-app (brotli/gzip, streaming-safe) and precompress
  the node build so local and CI measurements match production
- Validate the Supabase session once per request
- Render the homepage immediately and stream public stats
- Stream a Pokedex's entries with the page instead of fetching after
  hydration, running the rows and count queries in parallel
- Shrink the avatar and offline placeholder images, fix layout shift,
  contrast, link names and missing meta descriptions
- Add Lighthouse CI (mobile + desktop) with score and metric budgets,
  bundle-size budgets in the build tests, and signed-in speed scenarios
This commit is contained in:
Josh Creek
2026-09-14 20:53:53 +01:00
parent 556f120f16
commit ff29095c47
30 changed files with 4166 additions and 487 deletions
+57
View File
@@ -0,0 +1,57 @@
import { describe, expect, it, vi } from 'vitest';
const getUser = vi.fn();
const getSession = vi.fn();
vi.mock('$env/static/public', () => ({
PUBLIC_SUPABASE_URL: 'http://127.0.0.1:54321',
PUBLIC_SUPABASE_ANON_KEY: 'anon'
}));
vi.mock('@supabase/ssr', () => ({
createServerClient: () => ({ auth: { getUser, getSession } })
}));
const { handle } = await import('../../src/hooks.server');
async function runHandle() {
const event = {
cookies: { getAll: () => [], set: vi.fn() },
locals: {}
} as unknown as Parameters<typeof handle>[0]['event'];
await handle({ event, resolve: vi.fn(async () => new Response()) } as never);
return event.locals;
}
describe('safeGetSession', () => {
it('validates the session with Supabase Auth only once per request', async () => {
getUser.mockReset().mockResolvedValue({ data: { user: { id: 'user-1' } }, error: null });
getSession.mockReset().mockResolvedValue({ data: { session: { access_token: 't' } } });
const locals = await runHandle();
const [first, second] = await Promise.all([locals.safeGetSession(), locals.safeGetSession()]);
const third = await locals.safeGetSession();
expect(getUser).toHaveBeenCalledTimes(1);
expect(first.user?.id).toBe('user-1');
expect(second).toBe(first);
expect(third).toBe(first);
});
it('does not share a session between requests', async () => {
getUser.mockReset().mockResolvedValue({ data: { user: { id: 'user-1' } }, error: null });
getSession.mockReset().mockResolvedValue({ data: { session: {} } });
await (await runHandle()).safeGetSession();
await (await runHandle()).safeGetSession();
expect(getUser).toHaveBeenCalledTimes(2);
});
it('returns no session when the JWT is rejected', async () => {
getUser.mockReset().mockResolvedValue({ data: { user: null }, error: new Error('bad jwt') });
getSession.mockReset();
const locals = await runHandle();
await expect(locals.safeGetSession()).resolves.toEqual({ session: null, user: null });
expect(getSession).not.toHaveBeenCalled();
});
});