← Назад к вопросам

Что такое FSD-архитектура?

2.0 Middle🔥 171 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

FSD архитектура (Feature-Sliced Design)

FSD (Feature-Sliced Design) - это современная архитектура организации кода в frontend приложениях, разработанная специально для масштабируемых React/Vue приложений. Она решает проблему быстрого роста сложности кодовой базы.

Проблема без правильной архитектуры

Обычная структура растет хаотично:

src/
  components/
    Button.tsx
    Header.tsx
    Footer.tsx
    UserProfile.tsx
    ProductCard.tsx
    ... 50+ файлов
  pages/
    Home.tsx
    Products.tsx
  utils/
    api.ts
    helpers.ts
    ... много всего
  hooks/
    ... куча хуков

Проблемы:

  • Непонятна структура
  • Сложно найти нужный файл
  • Когда менять компонент - неясно, что еще сломается
  • Невозможна переиспользуемость

FSD решение

FSD структурирует код по "слайсам" (features) с четкими уровнями абстракции:

src/
  shared/              # Переиспользуемое везде
    ui/               # UI компоненты (Button, Input)
    lib/              # Функции утилиты (formatDate, cn)
    config/           # Конфигурация приложения
  entities/           # Бизнес-сущности (User, Product, Post)
    user/
      ui/
        UserCard.tsx
      model/
        userSlice.ts
        userAPI.ts
      index.ts
    product/
      ui/
        ProductCard.tsx
      model/
        productAPI.ts
      index.ts
  features/           # Функции (AddToCart, Login, Search)
    auth/
      ui/
        LoginForm.tsx
      model/
        authSlice.ts
      index.ts
    search/
      ui/
        SearchBar.tsx
      model/
        searchAPI.ts
  pages/              # Страницы (маршруты)
    home/
      HomePage.tsx
    products/
      ProductsPage.tsx
  app/                # Инициализация приложения
    App.tsx
    Router.tsx

Четыре слоя FSD

1. Shared (Общий)

Код переиспользуемый во всем приложении:

// src/shared/ui/Button.tsx
export interface ButtonProps {
  children: React.ReactNode;
  onClick?: () => void;
  variant?: 'primary' | 'secondary';
}

export function Button({ children, variant = 'primary', onClick }: ButtonProps) {
  return (
    <button className={`btn btn-${variant}`} onClick={onClick}>
      {children}
    </button>
  );
}
// src/shared/lib/utils.ts
export function formatDate(date: Date): string {
  return new Intl.DateTimeFormat('ru-RU').format(date);
}

export function cn(...classes: (string | undefined)[]): string {
  return classes.filter(Boolean).join(' ');
}

Правило: shared не знает о features и entities.

2. Entities (Сущности)

Бизнес-модели - User, Product, Post, Comment:

// src/entities/product/model/types.ts
export interface Product {
  id: string;
  name: string;
  price: number;
  rating: number;
  image: string;
}

// src/entities/product/ui/ProductCard.tsx
import { Product } from '../model/types';

export function ProductCard({ product }: { product: Product }) {
  return (
    <div className="product-card">
      <img src={product.image} alt={product.name} />
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <span>{product.rating}/5</span>
    </div>
  );
}

// src/entities/product/index.ts - экспортируем API
export type { Product };
export { ProductCard };
export { useProduct } from './model/useProduct';

Правило: entities содержат модель данных и UI. Не содержат бизнес-логику конкретного flow.

3. Features (Функциональность)

Визуальные взаимодействия - Login, AddToCart, Search:

// src/features/add-to-cart/model/addToCartAPI.ts
export async function addToCart(productId: string, quantity: number) {
  const response = await fetch('/api/cart', {
    method: 'POST',
    body: JSON.stringify({ productId, quantity }),
  });
  return response.json();
}

// src/features/add-to-cart/ui/AddToCartButton.tsx
import { useState } from 'react';
import { Button } from '@/shared/ui';
import { addToCart } from '../model/addToCartAPI';

export function AddToCartButton({ productId }: { productId: string }) {
  const [loading, setLoading] = useState(false);

  const handleClick = async () => {
    setLoading(true);
    try {
      await addToCart(productId, 1);
      alert('Added to cart!');
    } finally {
      setLoading(false);
    }
  };

  return (
    <Button onClick={handleClick} disabled={loading}>
      {loading ? 'Adding...' : 'Add to Cart'}
    </Button>
  );
}

// src/features/add-to-cart/index.ts
export { AddToCartButton } from './ui/AddToCartButton';

Правило: features используют entities и shared, но не знают друг о друге.

4. Pages (Страницы)

Маршруты - Home, Products, Cart:

// src/pages/products/ProductsPage.tsx
import { useEffect, useState } from 'react';
import { ProductCard } from '@/entities/product';
import { AddToCartButton } from '@/features/add-to-cart';
import { SearchBar } from '@/features/search';
import { fetchProducts } from '@/shared/lib/api';

export function ProductsPage() {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    fetchProducts().then(setProducts);
  }, []);

  return (
    <div>
      <SearchBar />
      <div className="products-grid">
        {products.map(product => (
          <div key={product.id}>
            <ProductCard product={product} />
            <AddToCartButton productId={product.id} />
          </div>
        ))}
      </div>
    </div>
  );
}

Правило: pages комбинируют features и entities для создания полной страницы.

Правила зависимостей FSD

Стрелка показывает направление зависимостей:

page →  feature → entity → shared
      ↗          ↗         ↗
    (могут пропускать слои если нужно)

Запрещено:

  • shared импортирует что-то еще
  • entity импортирует feature
  • feature импортирует другую feature
  • page импортирует из shared напрямую (должно идти через entity/feature)
// Плохо - нарушение правил
// src/features/auth/ui/LoginForm.tsx
import { SearchBar } from '@/features/search'; // Нельзя! Features не знают друг о друге

// Хорошо
// src/pages/home/HomePage.tsx
import { LoginForm } from '@/features/auth';
import { SearchBar } from '@/features/search';
// Page может импортировать обе feature

Структура slice (слайса)

Каждый slice (feature или entity) имеет стандартную структуру:

features/add-to-cart/
  ui/              # Компоненты
    AddToCartButton.tsx
  model/           # Логика и API
    addToCartAPI.ts
    useAddToCart.ts
  lib/             # Утилиты этого slice
    constants.ts
  index.ts         # Public API слайса
// src/features/add-to-cart/index.ts - Экспортируем только нужное!
export { AddToCartButton } from './ui/AddToCartButton';
export type { CartItem } from './model/types';
// НЕ экспортируем API функции

Плюсы FSD

  1. Масштабируемость - новые разработчики сразу понимают структуру
  2. Переиспользуемость - features не зависят друг от друга
  3. Изоляция - изменение одного slice не сломает другой
  4. Отсутствие циклических зависимостей - четкие правила
  5. Тестируемость - каждый slice можно тестировать отдельно

Минусы FSD

  1. Кривая обучения - нужно понять правила
  2. Много папок - структура глубокая
  3. Может быть оверинжинирингом для маленького проекта
  4. Требует дисциплины - легко нарушить правила

Когда использовать FSD

  • Используй для enterprise приложений (50+ компонентов)
  • Используй для team проектов
  • Не используй для маленьких проектов (landing, todo)

Эмпирическое правило

Если в проекте:

  • Менее 5 страниц → простая структура
  • 5-20 страниц → рассмотри FSD
  • Более 20 страниц → FSD обязательна

Вывод

FSD - это best practice для организации больших frontend приложений. Она решает проблему хаоса в растущей кодовой базе и позволяет команде эффективно работать над проектом.