Структура каталогов по функциональным возможностям
Организуйте код по предметной области функций, а не по типам, храните тесты, стили и компоненты рядом и устанавливайте границы с помощью eslint-plugin-boundaries
«Структура каталогов по функциональным возможностям» — бесплатный урок Frontend Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Frontend Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Frontend Academy содержит 4 уроков всего.
Два способа организовать код
Код можно группировать по типу (components/, hooks/, services/, types/) или по функциональности (auth/, checkout/, dashboard/ — каждая папка содержит собственные компоненты, хуки и так далее). Для приложений среднего и большого размера лучше подходит группировка по функциональности.
Группировка по типу — классическая ловушка
Классическая структура учебника по React группирует всё по типу. При масштабировании она быстро создаёт проблемы: каждое изменение файла затрагивает несколько несвязанных папок, а чтобы «найти весь код оформления заказа», приходится искать по всему дереву с помощью grep.
// Type-based (avoid for large apps):
src/
components/
Button.tsx
LoginForm.tsx
CartItem.tsx
hooks/
useAuth.ts
useCart.ts
services/
auth.ts
cart.ts
types/
User.ts
CartItem.tsСтруктура по функциональности
Группируйте всё, что относится к одной функциональности, в одной папке. Такой код легко найти, удалить и понять.
src/
features/
auth/
LoginForm.tsx
SignupForm.tsx
useAuth.ts
auth.service.ts
auth.types.ts
auth.test.tsx
cart/
CartItem.tsx
CartSummary.tsx
useCart.ts
cart.service.ts
cart.types.ts
shared/
components/
Button.tsx
hooks/
useDebounce.tsСовместное размещение внутри функциональности
Папка функциональности содержит компоненты, хуки, сервисы, типы и тесты — весь код, необходимый для этой предметной области. Нужно понять, как устроена аутентификация? Откройте auth/. Хотите удалить аутентификацию? Удалите папку.
Общий код и код функциональности
Код, используемый двумя и более функциональностями, переносите в shared/ (или lib/). Код, используемый одной функциональностью, оставляйте внутри неё. Не извлекайте код только потому, что «возможно, он пригодится позже»: дождитесь второго использования.
Правила границ функциональностей
Функциональности не должны напрямую импортировать код друг из друга. Если двум функциональностям нужен общий код, вынесите его в shared/. Если им нужно координировать работу, используйте события или общее хранилище на уровне приложения.
Контроль границ с помощью ESLint
Используйте eslint-plugin-boundaries или eslint-plugin-import, чтобы обеспечить правило: функциональности могут импортировать код из shared, но не друг из друга.
// .eslintrc.json
{
"plugins": ["boundaries"],
"settings": {
"boundaries/elements": [
{ "type": "feature", "pattern": "src/features/*" },
{ "type": "shared", "pattern": "src/shared/*" }
]
},
"rules": {
"boundaries/element-types": ["error", {
"default": "disallow",
"rules": [
{ "from": "feature", "allow": ["shared"] },
{ "from": "shared", "allow": ["shared"] }
]
}]
}
}Публичный API каждой функциональности
Каждая функциональность экспортирует публичный API через features/auth/index.ts. Остальной код импортирует его из '@/features/auth', а не по глубоким путям. Это позволяет менять внутреннюю реализацию, не нарушая работу потребителей.
// features/auth/index.ts
export { LoginForm } from './LoginForm';
export { useAuth } from './useAuth';
export type { User, AuthState } from './auth.types';
// Consumers:
import { LoginForm, useAuth } from '@/features/auth';
// NOT: import { LoginForm } from '@/features/auth/LoginForm';Вложенные функциональности
Крупные функциональности могут содержать вложенные папки: dashboard/widgets/, dashboard/charts/. Не углубляйте структуру более чем на 2–3 уровня — поиск станет мучительным.
Где размещать маршруты
Страницы и маршруты можно хранить в папке верхнего уровня pages/ или routes/. Они должны быть тонкими: получать компоненты и хуки из функциональностей и объединять их.
src/
pages/
Dashboard.page.tsx // composes Dashboard widgets from features/dashboard/
Cart.page.tsx // composes from features/cart/
features/
shared/Перенос существующего приложения
Начните только с новых функциональностей — помещайте новый код в features/. Не переделывайте всё сразу. По мере работы со старыми файлами постепенно переносите их. Правила границ ESLint предотвращают возврат к прежней структуре.
Когда группировка по типу всё ещё подходит
Для очень небольших приложений (менее 30 компонентов) или библиотек группировка по типу вполне подходит. Переходите к группировке по функциональности, как только появятся отдельные бизнес-области: аутентификация, оформление заказа, платежи и настройки.
Быстрая проверка
Какое главное преимущество с точки зрения организации кода даёт группировка по функциональности вместо группировки по типу файла?
Итоги: структура по функциональности
В features/ находится код, относящийся к конкретным предметным областям; в shared/ — утилиты, используемые разными функциональностями. Каждая функциональность экспортирует публичный index.ts. Функциональности не импортируют код друг из друга — только из shared. Границы контролируются с помощью eslint-plugin-boundaries. Страницы и маршруты объединяют функциональности. Перенос выполняйте постепенно. Для небольших приложений подходит группировка по типу.
Часто задаваемые вопросы
Урок «Структура каталогов по функциональным возможностям» бесплатный?
Да — полный текст урока «Структура каталогов по функциональным возможностям» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Frontend Academy, подпишись на CoddyKit PRO. Курс Frontend Academy содержит 4 уроков всего.
Чему я научусь в уроке «Структура каталогов по функциональным возможностям»?
Организуйте код по предметной области функций, а не по типам, храните тесты, стили и компоненты рядом и устанавливайте границы с помощью eslint-plugin-boundaries Ты практикуешь Frontend Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Frontend Academy?
Предыдущий опыт не требуется. Frontend Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Структура каталогов по функциональным возможностям»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Frontend Academy?
Да. Каждый урок Frontend Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Атомарный дизайн: атомы, молекулы и организмы
- Настройка монорепозитория с Turborepo
- Микрофронтенды: Module Federation
- Структура каталогов по функциональным возможностям