Заметки об app router в Next.js 15
Я перенёс панель среднего размера с pages router на app router в Next.js 15 — где-то за три недели, попутно с обычной работой над фичами. Вот заметки, которые хотел бы иметь под рукой до того, как начал.
Что изменилось
Главный сдвиг — в голове: роутинг теперь это дерево папок, и у каждой папки может быть свой layout, свой loading-стейт и свой error boundary. getServerSideProps и getStaticProps исчезли — данные загружаются прямо в серверных компонентах, обычными async-функциями. Route handlers заменили API routes: один route.ts на сегмент вместо одного файла со switch по req.method.
Кеширование тоже изменило форму. Фетчи кешируются по умолчанию, если явно не отключить это — удобно, пока не забудешь, что это происходит, и не потратишь двадцать минут, разглядывая устаревшие данные. Теперь я по умолчанию ставлю новым фетчам { cache: 'no-store' } и включаю кеш осознанно, а не наоборот.
async function getInvoices(orgId: string) {
const res = await fetch(`${API}/invoices?org=${orgId}`, {
cache: 'no-store',
});
if (!res.ok) throw new Error('Не удалось загрузить счета');
return res.json();
}
Что удивило
Серверные компоненты сочетаются с клиентскими проще, чем я ожидал: данные, загруженные на сервере, спускаются вниз пропсами, и только интерактивный лист дерева становится 'use client'. Удивило не так приятно другое — как легко случайная директива 'use client' в общем файле-утилите утягивает половину дерева в клиентский бандл. Я нашёл три таких случая почти случайно, просматривая bundle analyzer.
useSearchParams тоже принудительно переводит компонент в клиентский рендеринг целиком — это легко упустить, когда переписываешь страницу, которая раньше бесплатно читала router.query.
Что сделал бы иначе
Я бы сначала на бумаге провёл границу между сервером и клиентом, а не постфактум. Ещё завёл бы route groups с первого дня, а не добавлял их задним числом — переструктурировать папки, когда роуты уже стали боевыми URL, куда нервознее, чем должно быть. И написал бы loading.tsx заранее, а не как довесок: именно они меняют ощущение от всей миграции, потому что приложение перестаёт выглядеть сломанным, пока данные стримятся.
Итог: изменение хорошее, но app router вознаграждает тех, кто решил форму серверно-клиентского разделения до начала работы, а не посреди миграции.