Коротка відповідь
Залиште app композицію URL і правила фреймворку, локальний UI — біля маршруту, повторну бізнес-поведінку — в модулях функцій. Явно відокремте серверні дані від браузера. Зручна структура дає простежити URL, дозволені дані й результат, а не лише розкласти все в components, hooks, services і utils.
Практичні кроки реалізації
1. Пояснюйте маршрут файлами фреймворку
page.tsx є точкою сторінки, layout.tsx — спільним UI, loading.tsx — fallback сегмента, error.tsx — межею помилки. Звичайні файли не створюють маршрут без page чи route. Папки з підкресленням виключаються з маршрутизації, групи в дужках не додають назву до URL.
2. Виносьте стабільну доменну відповідальність
Для умовного бронювання відокремте публічне читання доступності, дозволений запис і компоненти відображення. Називайте exports за операціями, а не загальним service-об’єктом. Виносьте з маршруту за реальної повторної потреби. Загальний helpers приховує власність; модуль має зрозумілу причину зміни й виклик.
3. Зробіть середовище явним
Назва .server.ts показує намір; import server-only зупиняє клієнтський імпорт під час збірки. Усередині залишаються ключі й клієнт бази. Client Components отримують невеликі публічні поля. Спільні типи виносьте за потреби. Не змішуйте серверні адаптери й браузерні компоненти в одному barrel.
4. Не перевантажуйте layout
Кореневий layout задає документ і спільну оболонку. Providers функції розміщуйте біля потрібних маршрутів. Перевірка в layout не замінює авторизацію читання чи прямого серверного виклику. Фіксуйте залежності між функціями, щоб перенесення не створило циклу.
Приклад реалізації
Невеликий серверний модуль використовує умовний локальний контент. У застосунку публічні поля формують після дозволеного чи явно публічного читання. Модуль доступний сторінці, але не графу імпортів Client Component. Next.js обробляє server-only і перевіряє межу при збірці.
// src/features/articles/read-public-article.server.ts
import "server-only";
type PublicArticle = { slug: string; title: string };
const published: PublicArticle[] = [
{ slug: "structure", title: "Project structure" },
];
export async function readPublicArticle(slug: string) {
const article = published.find((entry) => entry.slug === slug);
return article ? { slug: article.slug, title: article.title } : null;
}
Портфоліо вже розділяє src/app, src/lib для контенту й перекладів, src/components і src/content/blog. Це спостережувані обов’язки, не універсальні назви. Нова функція має спочатку вписатися в межі, а не запускати перебудову всього репозиторію.
Компроміси та альтернативи
Colocation спрощує навігацію, модулі функцій узгоджують спільні правила. Невеликий сайт може бути пласким, великий продукт — доменним. Окремі пакети потребують незалежних користувачів чи перевірок. Спочатку забезпечте напрям імпортів, потім додавайте папки.
Поширені помилки
Поширені збої: кореневий use client, utils із секретами й форматуванням, авторизація лише в page. Групи маршрутів змінюють організацію, не політику доступу. Перенесення файлів без оновлення імпортів, метаданих і динамічних маршрутів має runtime-наслідки.
Перевірка перед випуском
- URL простежується до даних і результату.
- Серверні адаптери мають server-only і публічні поля.
- Клієнтські імпорти не містять привілейованих залежностей.
- Providers і межі помилок розташовані біля маршрутів.
- Групи не створюють однакових URL.
- Напрям імпортів визначено.
Поширені запитання
Чи треба виносити всі файли з app?
Ні. Next.js підтримує colocation. Переносьте заради власності чи повторного використання, не через хибне припущення, що звичайні файли app стають маршрутами.
Чи папка server захищає функцію?
Ні. Маркери середовища контролюють імпорти, авторизація — доступ. Потрібні обидва; папки й типи не перевіряють викликачів.
Наступний крок
Простежте маршрут і позначте URL, бізнес-правила, зовнішні дані й браузер. Перенесіть лише неоднозначні обов’язки. Структура має спростити наступну зміну без нової системи папок для кожної функції.
Первинні джерела
Пов’язані матеріали та приклади
Потрібно реалізувати це у вашому продукті?
Перегляньте відповідні приклади продуктів або поділіться контекстом розробки вебзастосунку, розширення Chrome, API чи SaaS.