Feature-Sliced Design: архитектура фронтенда для больших проектов
Продвинутое4 минРедакция Innovialabs
Коротко
Feature-Sliced Design делит фронтенд на слои по уровню ответственности, слои — на слайсы по бизнес-доменам, а слайсы — на технические сегменты; модуль может импортировать только из нижележащих слоёв и только через публичный API слайса.
Что такое Feature-Sliced Design
Feature-Sliced Design (FSD) — методология, которая структурирует фронтенд-код по бизнес-смыслу, а не по типу файлов. Вместо одной огромной папки components/ и hooks/ код группируется в слои, слайсы и сегменты с одним строгим правилом: зависимости направлены только вниз. В результате фичу можно найти, изменить или удалить, не сломав несвязанные части.
Слои
Слои — папки верхнего уровня, от самых конкретных к самым общим:
| Слой | Назначение | Пример |
|---|---|---|
| app | Инициализация: провайдеры, роутинг, глобальные стили | Провайдер темы, настройка стора |
| pages | Целые страницы, собранные из нижних слоёв | Страница товара, профиль |
| widgets | Крупные самостоятельные блоки интерфейса | Шапка, список товаров с фильтрами |
| features | Действия пользователя, несущие бизнес-ценность | Добавить в корзину, войти, оставить отзыв |
| entities | Бизнес-сущности | Пользователь, товар, заказ |
| shared | Переиспользуемый код без бизнес-логики | UI-кит, API-клиент, утилиты |
В старой документации упоминается слой processes — он устарел, а его логика обычно переезжает в features или app. Все слои не обязательны: небольшие проекты часто обходятся app, pages, shared и парой сущностей.
Слайсы и сегменты
Слайсы делят слой по бизнес-доменам: entities/user, entities/product, features/add-to-cart. У слоёв app и shared слайсов нет.
Сегменты делят слайс по техническому назначению. Типичные названия:
ui— компонентыmodel— состояние, сторы, бизнес-логикаapi— запросы к бэкендуlib— вспомогательный код этого слайсаconfig— константы и флаги
Правила импорта и публичный API
FSD держится на двух правилах:
- Модуль импортирует только из слоёв строго ниже. Фича может использовать entities и shared, но не widgets и не другую фичу. Слайсы одного слоя друг друга не импортируют.
- У каждого слайса есть публичный API — файл
index.ts. Остальной код импортирует только из него, никогда из внутренних путей.
// entities/product/index.ts
export { ProductCard } from "./ui/product-card";
export { useProduct } from "./model/use-product";
export type { Product } from "./model/types";
// правильно
import { ProductCard } from "@/entities/product";
// неправильно: лезем во внутренности
import { ProductCard } from "@/entities/product/ui/product-card";
Линтер Steiger и ESLint-плагины для границ модулей проверяют эти правила автоматически, и архитектура не зависит только от код-ревью.
Если две сущности действительно нужны друг другу (заказ ссылается на пользователя), FSD предлагает нотацию кросс-импорта через @x — явное, контролируемое исключение. Используйте её редко.
Пример структуры на Next.js
Папка app/ в Next.js совпадает по имени со слоем app в FSD. Распространённое решение: оставить роутинг Next.js в корневой app/ в виде тонких файлов, которые реэкспортируют FSD-страницы, а код FSD перенести в src/.
app/ # только роутинг Next.js
products/[id]/page.tsx # export { ProductPage as default } from "@/pages/product"
src/
app/ # провайдеры, глобальные стили
pages/
product/
ui/product-page.tsx
index.ts
widgets/
product-gallery/
features/
add-to-cart/
ui/add-to-cart-button.tsx
model/use-add-to-cart.ts
index.ts
entities/
product/
api/get-product.ts
ui/product-card.tsx
model/types.ts
index.ts
shared/
ui/button.tsx
api/http.ts
Осторожнее и с именем pages: Next.js может воспринять папку pages (в том числе src/pages) как маршруты Pages Router. В официальном руководстве FSD по Next.js описано, как избежать конфликта, — сверьтесь с ним, прежде чем фиксировать структуру.
Миграция существующего проекта
Не переписывайте всё разом. Постепенный путь:
- Создайте
sharedи перенесите туда UI-кит, API-клиент и утилиты. - Выделите главные сущности, о которых говорит приложение (пользователь, товар, заказ).
- Затем перенесите страницы и держите их тонкими: они собирают, а не содержат логику.
- Выделяйте фичи по мере того, как трогаете код в новых задачах.
- Когда структура устоится, включите линтинг правил импорта и исправляйте нарушения постепенно.
Самая частая сложность — понять, что фича, а что сущность. Практический тест: сущность — существительное (товар), фича — глагол, действие пользователя (добавить товар в корзину).
Когда FSD избыточен
- Лендинги, небольшие маркетинговые сайты и прототипы.
- Короткоживущие MVP, где скорость важнее структуры.
- Один разработчик и небольшое приложение на несколько экранов.
- Команды, которые не будут соблюдать правила: наполовину внедрённый FSD хуже простой, но последовательной структуры.
FSD окупается на проектах с несколькими разработчиками, множеством фич и долгой жизнью.