Feature-Sliced Design
Feature-Sliced Design (FSD) — методология организации файловой структуры фронтенд-приложения, делящая код на слои (layers) и нарезки по фичам (slices) с явными правилами зависимостей между ними.
Зачем нужно
Без чёткой структуры большое приложение превращается в «спагетти»: components/ с сотнями файлов без классификации, circular imports, непонятно где добавлять новый код. FSD решает это через стандартизацию: каждый разработчик знает куда положить файл и что может импортировать. Правило «слой может импортировать только из слоёв ниже» предотвращает circular deps и сложные зависимости.
Где используется
- Крупные SPA с несколькими фичами и командами
- React/Vue/Angular проекты с желанием стандартизировать структуру
- Распространено в русскоязычном сообществе; набирает популярность глобально
Структура FSD
src/
├── app/ ← 7. Настройки приложения, провайдеры, роутер
├── pages/ ← 6. Страницы (композиция виджетов)
├── widgets/ ← 5. Самостоятельные секции страниц (Header, Sidebar)
├── features/ ← 4. Пользовательские сценарии (auth, cart-add)
├── entities/ ← 3. Бизнес-сущности (User, Product, Order)
├── shared/ ← 2. Переиспользуемый код без бизнес-логики
└── (processes/) ← 1. Устаревший слой, редко используется
Правило: каждый слой может импортировать только из слоёв ниже себя.
features → entities → shared: допустимо.
shared → features: запрещено.
Структура слайса
features/
auth/ ← слайс "авторизация"
ui/ ← компоненты LoginForm, AuthButton
model/ ← store, actions, selectors (state)
api/ ← запросы к API
lib/ ← утилиты для фичи
index.ts ← публичный API слайса (единственная точка импорта)
Пример: product-card фича
entities/
product/
ui/
ProductCard.tsx ← карточка товара
ProductPrice.tsx ← цена с форматированием
model/
productModel.ts ← тип Product, селекторы
api/
productApi.ts ← fetch /api/products/:id
index.ts ← export { ProductCard, productModel, productApi }
features/
add-to-cart/
ui/
AddToCartButton.tsx ← кнопка добавления
model/
cartStore.ts ← zustand store корзины
index.ts
pages/
product-page/
ui/
ProductPage.tsx ← компонует entities + features
// ProductPage.tsx — только импорты из слоёв ниже
import { ProductCard } from 'entities/product';
import { AddToCartButton } from 'features/add-to-cart';
// НЕ: import что-то из 'pages/another-page'
Публичный API слайса (index.ts)
// entities/product/index.ts
// Только то, что разрешено использовать снаружи
export { ProductCard } from './ui/ProductCard';
export { ProductPrice } from './ui/ProductPrice';
export type { Product } from './model/productModel';
// Внутренние детали НЕ экспортируются
// Использование:
import { ProductCard, type Product } from 'entities/product';
// НЕ: import { ProductCard } from 'entities/product/ui/ProductCard'
Частые ошибки
- Нарушение правила зависимостей —
sharedимпортирует изfeatures; используйте линтер@feature-sliced/eslint-pluginдля автоматической проверки. - Слишком мелкие слайсы — создают слайс для каждого компонента; слайс должен соответствовать бизнес-сущности или фиче, а не UI-элементу.
- Игнорируют
index.ts— импортируют напрямую из внутренних файлов (entities/product/ui/ProductCard), нарушая инкапсуляцию.