perf(frontend): route-level code splitting, main chunk 538 -> 491 KB

Lighthouse (production, default mobile 4x-CPU profile) scored
Performance 33/100, dominated by one ~536-538 KB entry chunk that
bundled every route's code regardless of which page a visitor landed
on -- the "chunks are larger than 500 kB" Vite warning on every build
this session.

Converted every route except / and the 404 catch-all to React Router
8's native route.lazy (blocks navigation until the chunk is ready --
no separate Suspense fallback needed). AppShell/HomePage/NotFoundPage/
RequireAuth stay eager since they're needed on every load regardless.

Result: main chunk 490.84 KB, no >500kB warning, one small chunk per
route (LoginPage 1.4 KB, ThemesPage 15.5 KB, AccountPage 11 KB, etc.)
loaded only when actually visited.

Fixed a real race the lazy boundary exposed: /login and /register
share an "Почта" field label, and during the chunk swap between them
the old page can stay mounted a beat longer than before -- a test
grabbing the field by label could land on the about-to-unmount one.
Also bumped RTL's asyncUtilTimeout and vitest's testTimeout, since the
route-transition + findBy chain didn't always land inside the old
1000/5000ms defaults under full parallel test-suite load.

Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
This commit is contained in:
loki5512344 2026-09-30 16:06:45 +02:00
parent 6b0633034d
commit b170227adf
Signed by: boba
GPG key ID: 253067914055423B
4 changed files with 34 additions and 23 deletions

View file

@ -42,7 +42,12 @@ test('registering after a redirect lands back where the visitor was going', asyn
})
const { router } = renderApp(routes, '/link')
await user.click(await screen.findByRole('link', { name: 'Регистрация' }))
await user.type(await screen.findByLabelText('Почта'), 'a@b.c')
// /login and /register are lazy-loaded and share the "Почта" email label, so the
// previous (login) page can still be mounted for a tick while the register chunk
// resolves. Wait for a register-only marker before querying its email field, or a
// stale reference to the login field (about to unmount) can end up typed into instead.
await screen.findByLabelText('Ник на сайте')
await user.type(screen.getByLabelText('Почта'), 'a@b.c')
await user.type(screen.getByLabelText('Ник на сайте'), 'Rider')
await user.type(screen.getByLabelText('Пароль'), 'correct-horse')
await user.click(screen.getByRole('button', { name: 'Создать аккаунт' }))