Урок по треку Архитектура фронтенда 7 мин

Feature-Sliced Design за 7 минут

Слои, слайсы, сегменты, публичный API и правило импортов в FSD.

Feature-Sliced Design (FSD) это методология структуры фронтенд-проекта. Её цель: чтобы по пути файла было понятно, за что он отвечает, и чтобы зависимости шли в одну сторону. В российских компаниях FSD спрашивают часто, потому что многие проекты на ней живут.

Три уровня: слои, слайсы, сегменты

Слои (сверху вниз, актуальная версия методологии 2.x):

СлойЧто лежит
appинициализация: провайдеры, роутер, глобальные стили
pagesстраницы целиком (в FSD 2.x допускается держать здесь и код, нужный только одной странице)
widgetsкрупные самостоятельные блоки интерфейса: шапка, лента, сайдбар
featuresпользовательские действия, которые несут ценность: «добавить в корзину», «войти»
entitiesбизнес-сущности: пользователь, товар, заказ
sharedпереиспользуемое без бизнес-смысла: UI-кит, api-клиент, утилиты, конфиг

Слой processes объявлен устаревшим, его логику переносят в app или features.

Главное правило импортов: модуль может импортировать только из слоёв строго ниже себя. features может брать из entities и shared, но не из widgets. И слайсы одного слоя не импортируют друг друга: features/cart не лезет в features/auth.

Слайсы делят слой по бизнес-домену: entities/user, entities/product, features/add-to-cart. В app и shared слайсов нет, там сразу сегменты.

Сегменты делят слайс по техническому назначению: ui, model (стор, бизнес-логика), api, lib, config.

src/
  app/
  pages/product/
  widgets/product-card-list/
  features/add-to-cart/
    ui/AddToCartButton.tsx
    model/useAddToCart.ts
    index.ts          <- публичный API
  entities/product/
    ui/ProductCard.tsx
    model/types.ts
    api/getProduct.ts
    index.ts
  shared/ui/Button/

Публичный API

Каждый слайс экспортирует наружу только то, что разрешено, через index.ts. Снаружи импортируют @/entities/product, а не @/entities/product/ui/ProductCard. Тогда внутренности можно переставлять без правок по всему проекту.

Кросс-импорты сущностей

Иногда сущности ссылаются друг на друга: заказ содержит пользователя. Для этого в FSD есть нотация @x: entities/user/@x/order.ts явно экспортирует то, что разрешено брать сущности order. Это осознанное исключение, а не лазейка.

Как решить, куда положить код

  • Нет бизнес-смысла (кнопка, formatDate) → shared.
  • Это «что» в предметной области (товар, его тип, карточка) → entities.
  • Это «действие пользователя», от которого что-то меняется → features.
  • Это блок, который собирает несколько фич и сущностей → widgets.
  • Используется на одной странице и нигде больше → можно держать в pages.

Проверка соблюдения правил делается линтером: Steiger (официальный линтер FSD) или eslint-plugin-boundaries.

Частые ошибки

  • Складывать всё подряд в features: каждая кнопка становится фичей. Фича это действие с ценностью, а не любой компонент.
  • Импортировать из фичи в фичу. Если двум фичам нужно общее, это поднимается в widgets (композиция) или опускается в entities/shared.
  • Обход публичного API глубоким импортом.
  • shared превращается в свалку с бизнес-логикой.

Что спросят на собесе

  • Назови слои FSD и правило импортов между ними.
  • Чем фича отличается от сущности? Приведи пример.
  • Зачем публичный API у слайса?
  • Что делать, если двум фичам нужно общее?
  • Какие минусы у FSD?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.