- Frontend project structure
"Если бы строители строили здания так же, как программисты пишут программы, то первый дятел, который попадётся, разрушил бы цивилизацию."
Джеральд Вайнберг
Эта статья посвящена различным подходам к организации структуры проекта на React и Vue.js. Она предоставляет вводную информацию, как можно упорядочить файлы, компоненты и модули в больших и малых проектах, чтобы облегчить поддержку, масштабирование и командную разработку.
Основные цели:
- Обзор архитектурных подходов Flat, Atomic Design, Modules (Domain/Module-Based), Feature-Sliced и Microfrontends.
- Кратко рассказать плюсы и минусы каждого метода.
- Направить разработчиков в правильном направлении с выбором подходящей структуры в зависимости от масштаба и требований проекта.
- Подчеркнуть, что не существует единственно правильного способа — структура должна выбираться в зависимости от задач и команды.
Надеюсь, что, то немного что описано тут будет полезно не только новичкам, но и опытным разработчикам.
Архитектура frontend приложения нужна для организации и структурирования кода, что бы сделать приложение более удобным в разработке, поддержке и расширении.
Ключевые цели архитектурного проектирования современного веб-приложения.:
- Улучшить читаемость, поддержку и распределение ответственности в коде.
- Повысить гибкость архитектуры и упростить сопровождение.
- Снизить технический долг и упростить рефакторинг.
- Обеспечить гибкость развертывания и безопасность.
- Упростить работу команды и ускорить вывод продукта.
- Повысить производительность и масштабируемость.
- Ускорить цикл поставки и повысить стабильность.
- Обеспечить быстрый рост продукта.
Про архитектурные принципы на примере .NET-приложений можно почитать на странице из официального гида по современным веб-приложениям на .NET и Azure.
Последовательное соблюдение хороших принципов важно для качественного кода. Это означает применение принципов программирования вне зависимости от того, насколько быстро проект приближается к важному сроку.
Еще больше информации об архитектурных принципах на странице DevIQ: Principles.
В этом разделе будут кратко рассмотрены основные архитектурные подходы и методологии, которые применяются при разработке современных frontend-приложений.
Все компоненты, стили, утилиты и другие файлы проекта размещаются в одной или нескольких базовых папках без углубления по ролям или функциональности.
Например, все компоненты могут быть в папке components/, а страницы — в pages/.
Плюсы:
- Быстрый старт разработки
- Простота в понимании и быстрая реализация.
- Хорошо подходит для прототипов, MVP и небольших приложений.
- Минимальные накладные расходы на организацию.
Минусы:
- С ростом кода становится трудно поддерживать.
- Могут возникнуть конфликты имён.
- Нет чёткого разделения ответственности.
- Может привести к смешиванию бизнес-логики.
- Нет масштабируемости — сложнее внедрять новые фичи без рефакторинга.
Подходит для небольших проектов и прототипов. Идеальна, когда команда состоит из одного-двух разработчиков или когда важна скорость начала разработки. Структура проста для понимания и не требует дополнительной документации.
Базируется на концепции из дизайна, где UI разбивается на иерархические компоненты: атомы (базовые элементы), молекулы (комбинации атомов), организмы (сложные блоки), шаблоны и страницы. Этот подход обеспечивает четкую структуру компонентов от простых до сложных.
Плюсы:
- Отличная переиспользуемость компонентов.
- Логичное и последовательное разделение уровней UI.
- Упрощает взаимодействие с дизайнерскими системами.
Минусы:
- Требует глубокого понимания концепции.
- Может быть избыточным для малых проектов.
- Не охватывает бизнес-логику или маршрутизацию.
Хорошо подходит для проектирования сложных UI-библиотек и повторно используемых компонентов, особенно в компаниях с сильной дизайн-системой.
Проект делится на модули по бизнес-логике или разделам приложения (например, auth, dashboard, profile).
Каждый модуль содержит всё необходимое: компоненты, сторы, стили, тесты и др. и представляет собой мини-приложение внутри основного приложения.
Плюсы:
- Хорошая изоляция функциональности.
- Упрощает поддержку и тестирование отдельных частей приложения (модулей).
- Удобно работать в команде — можно разделить модули между разработчиками.
Минусы:
- Возможен дублирующий код между модулями.
- Требуется структура на уровне архитектуры на основе бизнес-логики.
- Сложнее управлять зависимостями между модулями.
Подходит для средних и больших приложений, особенно если функциональность логично разбивается по доменам (например, админка, клиентская часть, API-интеграция). Отлично масштабируется и позволяет разделить ответственность между разными командами.
Современный архитектурный подход (методология если быть точным), который представляет собой современный подход к организации кода, где приложение разделяется на функциональные слои и фичи. Каждый слой имеет конкретную роль в архитектуре приложения.
Плюсы:
- Улучшает масштабируемость и читаемость.
- Облегчает работу в больших командах и при росте приложения.
- Хорошо поддерживает переиспользование и изоляцию фич.
Минусы:
- Порог входа выше — требует понимания концепции и определения правил.
- Нужна строгая дисциплина при разработке.
- Избыточен для небольших приложений.
Идеален для крупных приложений с долгим жизненным циклом и множеством фич. Часто применяется в крупных продуктах с требованиями к модульности.
В основе лежит применение принципов микросервисов к фронтенд-разработке, то есть разделение фронтенда на независимые приложения (микрофронтенды), каждый из которых разрабатывается и деплоится отдельно. Каждый микрофронтенд разрабатывается отдельными командами для разных частей интерфейса (например, корзина, личный кабинет, каталог).
Плюсы:
- Масштабируемость разработки: каждая команда работает независимо.
- Возможность использования разных стеков технологий.
- Отдельный деплой, версионирование и обновления.
Минусы:
- Сложная инфраструктура: требует оркестрации, роутинга, стилей и состояний между микрофронтендами.
- Высокая стоимость поддержки.
- Проблемы с UX и согласованностью.
Актуально в enterprise-приложениях с множеством команд, когда требуется изолированная разработка и автономное развёртывание разных частей системы.
В рамках фронтенд-архитектуры Public API — это соглашение, при котором каждый модуль (например, компонент, фича, сущность или утилита) экспортирует наружу только нужные части своего интерфейса через файл index.ts в корне своей директории.
Этот файл выступает как точка входа, или "витрина", скрывающая внутреннюю реализацию и позволяющая удобно управлять зависимостями.
Пример:
/features/addTask
├── ui/
│ └── AddTaskForm.tsx
├── hooks/
│ └── useAddTask.ts
└── index.ts ← public API
// index.ts
export { AddTaskForm } from './ui/AddTaskForm';
export { useAddTask } from './hooks/useAddTask';Зачем нужен Public API
- Инкапсуляция - Позволяет скрыть внутреннюю структуру модуля: снаружи видно только то, что разрешено экспортом. Это уменьшает связанность между частями приложения и снижает риски при рефакторинге.
- Удобство импорта - Можно писать краткие и читаемые импорты:
вместо длинных путей к отдельным файлам.
import { AddTaskForm, useAddTask } from '@/features/addTask';
- Чистота зависимостей - Легче контролировать, что именно используется из модуля. В случае масштабирования можно быстро отследить, какие публичные части используются другими слоями приложения.
Ниже представлены упрощенные примеры вышеописанных подходов для приложения "Todo list", реализующего базовый функционал управления задачами, или ссылки на соответствующие репозитории документацию.
src/
├── components/
│ ├── TodoInput.tsx // Компонент ввода задачи
│ ├── TodoList.tsx // Список задач
│ ├── TodoItem.tsx // Отдельная задача
│ ├── TodoFilter.tsx // Компонент фильтрации
│ └── TodoCounter.tsx // Счетчик задач
├── hooks/
│ ├── useTodos.ts // Хук для управления задачами
│ └── useLocalStorage.ts // Хук для работы с localStorage
├── types/
│ └── todo.ts // Типы для задач
├── store/
│ └── todoStore.ts // Store для работы с хранилищем
├── App.tsx
└── index.tsxsrc/
├── components/
│ ├── atoms/
│ │ ├── Input.tsx // Базовый input
│ │ ├── Button.tsx // Базовая кнопка
│ │ └── Checkbox.tsx // Чекбокс
│ ├── molecules/
│ │ ├── TodoItem.tsx // Компонент задачи
│ │ └── Filter.tsx // Компонент фильтра
│ └── organisms/
│ ├── TodoList.tsx // Список задач
│ └── TodoForm.tsx // Форма добавления
├── hooks/
│ ├── useTodos.ts // Хук для управления localStorage
│ └── useLocalStorage.ts // Хук для управления задачами
├── types/
│ └── todo.ts // Типы для задач
├── stores/
│ └── todoStore.ts // Store для работы с хранилищем
├── App.tsx
└── index.tsxКонцепт методологии описан тут:
https://atomicdesign.bradfrost.com/table-of-contents/
src/
├── core/
│ ├── components/
│ │ └── Input.tsx // Базовый input
│ │ └── Button.tsx // Базовая кнопка
│ │ └── Checkbox.tsx // Чекбокс
│ └── hooks/
│ └── useLocalStorage.ts // Хук для управления localStorage
├── modules/
│ ├── todo/
│ │ ├── components/
│ │ │ ├── TodoInput.tsx // Компонент ввода задачи
│ │ │ ├── TodoList.tsx // Список задач
│ │ │ ├── TodoItem.tsx // Отдельная задача
│ │ │ └── TodoFilter.tsx // Фильтр задач
│ │ ├── hooks/
│ │ │ └── useTodos.ts // Хук для управления задачами
│ │ ├── types/
│ │ │ └── todo.ts // Типы для задач
│ │ └── store/
│ │ └── todoStore.ts // Store для работы с хранилищем
├── types/
│ └── index.ts
├── App.tsx
└── index.tsxСамый известный репозиторий с одной из реализаций на базе модульной архитектуры для React и Next.js:
Bulletproof React 🛡️ ⚛️
https://github.com/alan2207/bulletproof-react
От автора
Этот репозиторий предлагает один из подходов к созданию React-приложений с использованием лучших инструментов из экосистемы и хорошо структурированной архитектуры, которая отлично масштабируется. Основываясь на моем опыте работы с различными кодовыми базами, именно эта архитектура оказалась наиболее эффективной.
Цель репозитория — быть сборником ресурсов и лучших практик при разработке React-приложений. Он демонстрирует, как можно решать большинство реальных задач в приложении на практике, и помогает разработчикам писать более качественный код.
Не стесняйтесь изучить код примера приложения, чтобы получить максимум пользы из этого репозитория.
Официальный сайт https://feature-sliced.design/
База с примерами https://feature-sliced.design/examples
- Разделение обязанностей
- Компоненты UI (презентационные) не содержат бизнес-логику.
- Логика вынесена в хуки (use*) или сервисы.
- Обращения к API/хранилищу абстрагированы.
- Низкая связанность, высокая связность
- Компоненты и модули изолированы по назначению (например,
features,modules). - Сторонние зависимости инкапсулированы внутри слоёв.
- Переиспользуемый код вынесен в
shared.
- Компоненты и модули изолированы по назначению (например,
- Принципы SOLID (в контексте React)
- Компоненты решают одну задачу (SRP).
- Используются интерфейсы и абстракции для пропсов и API.
- Внедрение зависимостей через контексты и хуки (DIP).
- Вынесенная конфигурация
- Настройки (API_URL, флаги) — в
.env,config.tsилиcontext. - Конфигурация различается по средам (
.env.development,.env.production). - Нет "магических строк" или ключей прямо в JSX.
- Настройки (API_URL, флаги) — в
- Оптимизация для разработчиков
- Проект стартует одной командой (npm start, vite, next dev).
- Используются ESLint, Prettier, Husky, lint-staged.
- Есть Hot Reload/React Fast Refresh.
- Стратегическое кэширование
- Используется react-query, SWR или custom-кэш с TTL.
- Настроены stale-while-revalidate и кеш-инвалидация.
- Для localStorage/sessionStorage есть отдельные сервисы.
- Горизонтальное масштабирование
- Приложение stateless — все данные загружаются заново при монтировании.
- Хранилище (например, Zustand, Redux, MobX) легко сбрасывается.
- Нет использования локального файла или временного состояния вне React-цикла.
- Автоматизация
- Настроен CI (GitHub Actions, GitLab CI).
- Автотесты (Jest, Testing Library, Vitest) запускаются в pipeline.
- Сборка, деплой, preview запускаются автоматически.