Предисловие
Доброго времени суток, коллеги! В этой статье я делюсь своим способом упорядочивания папок и файлов для проектов на React/Next. Я fullstack разработчик с 10+ лет опыта коммерческой разработки, множество стартапов разработал в различных командах, и несколько стартапов разработал в одиночку, в т.ч. своих собственных.
В средних и крупных проектах присутствует огромное количество самописных модулей и компонентов, и важно оптимизировать их хранение, сделать файловую структуру простой и понятной для самого себя и других программистов, которые будут работать над проектом. Но как обеспечить хранение множества самых разнообразных компонентов, скриптов и модулей, чтобы дерево файлов не превращалось в кашу, и поиск нужного компонента происходил быстро, чтобы не приходилось искать его в длинном списке файлов?
Этот способ организации файлов по архитектуре MVC (model, view, controller) не претендует на истину в её последней инстанции, в то же время это подход, к которому я пришёл пройдя достаточно долгий путь, и подход, отлично зарекомендовавший себя своим удобством во множестве проектов. Поэтому если сочтёте информацию полезной - берите на вооружение. Если же у вас свой подход - можете поделиться им в комментариях, или написать отдельную статью. Я не ставлю цель разводить холивар на тему того что этот способ безупречен и лучше всех остальных, это лишь один из способов.
Я перечислю все используемые мной папки, если вы поймёте что какая либо папка вам в проекте не нужна - не создавайте её. Верно и обратное - если вам нужна какая либо папка, которой нет в данной статье, вы всегда можете усовершенствовать эту структуру, доработав её под себя.
Определимся с целью
Что мы хотим когда продумываем файловую структуру? Во первых чтобы у каждого файла с кодом было, в зависимости от того, что в этом файле находится, своё конкретное место. Когда мы хотим найти страницу - мы точно знаем в какой папке она находится. Когда мы хотим найти секцию, скрипт, или что-то ещё - аналогично. Если мы запихнём все компоненты в папку components - в среднем/крупном проекте у нас появится длиннющий список, и потребуется тратить лишнее время чтобы его листать, в поиске нужного компонента. Значит необходимо создавать подгруппы папок. Об этом и статья.
Начало работы:
После инициализации проекта почистим проект от мусорных файлов (стандартные файлы стилей, стартовый шаблон, и тд) и создадим основные папки. Если у вас конфигурация с папкой src - то в ней, если нет, то в корне проекта.
Для хранения JSX-компонентов я создаю папку react.
Зачем нам эта дополнительная папка? Чтобы папки с компонентами страниц, ui-компонентов, и прочая "вёрстка" были рядом друг с другом.
Когда у нас в корне папки components и pages, они сортируются по алфавиту, часто бывает, что нужно переключаться между файлами страниц и компонентов, и каждый раз листать дерево в поиске этих папок долго и неудобно.
Другое дело, когда они находятся рядышком, в одной папке!
В папке react сразу создадим следующие папки:
components - в ней будут компоненты: отдельные переиспользуемые части пользовательского интерфейса. мы их дополнительно сгруппируем по папкам внутри папки components, об этом я напишу ещё ниже, с подробной расшифровкой.
pages - в ней будут компоненты полноценных страниц. папка создаётся только для react, либо когда в next используется роутер отличный от классического, когда файлы страниц находятся в папке pages в корне проекта
views - в ней будут компоненты полноценных страниц, которые фактически могут быть использованы на разных страницах. если в проекте предполагается такая ситуация, для порядка имеет смысл хранить все страницы в папке views, а в компонентах в папке pages вызывать эти компоненты. если же таких ситуаций не предполагается, в react от этой папки можно отказаться. в next.js я в любом случае создаю эту папку, чтобы папки с файлами страниц были рядом с папками других JSX-компонентов.
sections - в ней будут компоненты представляющие из себя секции страниц. секция это скажем так одна из смысловых частей страницы. будем хранить все секции в этой папке, группируя по папкам с названием страницы. почему не создать по такой папке в папке каждой из страниц в pages? не редкость, когда секцию с одной страницы нужно использовать на другой странице, в то же время не каждая страница нуждается в том, чтобы дробить её на секции. используя данный подход, если нам нужно открыть файл именно какой либо секции, мы очень быстро найдём его.
popups - в ней будут компоненты модальных окон. как правило создаётся папка с мастер-компонентом, и рядом располагаются папки с модалками, созданными на основе этого компонента
Я специально не разместил последние 3 папки в папке components, по той причине, что в components у нас будет достаточно папок, а данные папки должны быть в быстром доступе. Что именно будет располагаться в components нуждается в подробном описании, и располагается ближе к концу статьи.
Для хранения JS-логики создадим папку scripts
В ней создадим следующие подпапки:
helpers - в ней будут располагаться вспомогательные функции, которые могут вызываться в разных частях проекта.
hooks - самописные React-хуки
backend - функции, взаимодействующие с бэкендом. они отправляют запрос, и возвращают данные. вся остальная логика происходит уже в месте их вызова
Для хранения глобальных стилей и шрифтов создадим папку styles
Глобальные стили - это общие стили, распространяющиеся на весь проект. Для отдельных компонентов я предпочитаю хранить стили в папке с компонентом, в отдельном файле. Буду показывать на примере scss, т.к. использую его чаще всего. Итак, создаём файлы:
global.scss - именно этот файл будет импортироваться в приложение, а также в этот файл будут импортироваться остальные файлы стилей из папки styles. Также в данном файле прописывается сброс стандартных css-стилей, и импортируются шрифты.
text.scss - в этом файле я прописываю атомарные стили для текста. Как правило в крупных проектах всё стандартизировано - заголовки, подзаголовки, тексты, и т.д.
variables.scss - в этом файле будут храниться остальные css-переменные
animations.scss - в этом файле соответственно хранятся стили css-анимаций
Если в проекте используются локальные шрифты, в папке styles следует создать папку fonts, и разместить их там
Для хранения JS-переменных создадим папку constants
В ней будут JS-файлы в которых переменные будут сгруппированы по смыслу из названия файла. К примеру у меня в этой папке могут находиться такие файлы как:
settings.js - какие-либо настройки
api.js - перечень всех адресов API бэкенда, именно эти переменные используются в запросах к серверу
secret.js - различные токены и секретные ключи. рядом с этим файлом располагается secret.example.js в котором есть переменные, но нет их значений, а сам secret.js находится в .gitignore
urls.js - различные внутренние и внешние ссылки для использования в разных частях проекта. так проще изменив одну переменную сразу автоматически применить изменение везде, где используется ссылка.
И так далее.
Для глобального состояния создадим папку store
И в ней создаём подпапки для файлов того типа глобального состояния, который используете вы (например actions, reducers, и тд). Лично я использую в значительном количестве случаев к сожалению не столь известный, но очень простой и доказавший свою эффективность модуль useGlobalHook, по которому я написал мини-гайд: Лёгкое в использовании глобальное хранилище состояния для React или Next: useGlobalHook.
Для хранения разных локализаций создадим папку locales
Только в том случае, если предполагается, что интерфейс проекта будет доступен более чем на одном языке. Тогда для каждого языка мы создадим отдельный js файл, содержащий переменные с текстом необходимой локализации.
Итак, основные папки мы создали!
Теперь погрузимся в содержимое папки /react/components. Как я писал выше, если мы просто запихнём все папки с компонентами в эту папку, у нас получится длинный список, который листать долго и неудобно. Поэтому компоненты мы будем группировать по папкам.
Объясняя данную концепцию коллегам, я столкнулся с тем, что зачастую неочевидно, какой компонент к какой подгруппе относится. Поэтому следующая часть статьи будет не просто описанием папок внутри папки components, а очень подробной расшифровкой какие компоненты должны лежать в этой папке, с примерами в виде скриншотов.
Ещё раз акцентирую внимание: все папки о которых пойдёт речь ниже, необходимо создавать в папке /react/components!
Папка containers
В ней располагаются компоненты, выполняющие функцию обёртки, т.е. компоненты, которые возвращают children.
К примеру это может быть компонент carcas - общая обёртка для всех страниц, выводящая помимо children компоненты header (шапка) и footer (подвал), а также содержащий мета-теги (с возможностью передачи кастомных тегов/состояний через props).
Пример return-а контейнера carcas:
Контейнеры разметок страницы (wrapper-ы, layout-ы), стандартизированные компоненты вывода текста, универсальные компоненты-контейнеры (как например универсальный сворачивающийся и разворачивающийся аккордеон на основе которого можно создать отдельные компоненты аккордеонов для конкретных ситуаций). Ну вы поняли.
Папка inputs
В ней располагаются отдельные компоненты благодаря которым пользователь приложения может вводить какую либо информацию - текстовые поля, чекбоксы, переключатели, кнопки, селекты и так далее.
Примеры компонентов, к-е должны находиться в папке inputs
Папка forms
Содержит компоненты, являющиеся сочетанием нескольких компонентов из папок inputs. Это может быть к примеру форма ввода логина и пароля (только текстовые поля и кнопка), или форма подписки на e-mail рассылку.
Примеры компонентов, к-е должны находиться в папке forms
Папка sliders
Содержит кастомные компоненты-слайдеры. Т.е. если нужно вывести где-то слайдер, обычно мы используем модуль, этот модуль тянет за собой кучу настроек и так далее. Для удобства мы создаём отдельный компонент в этой папке, в котором добиваемся чтобы слайдер выглядел как нам необходимо, и при помощи props добиваемся максимально простого использования и пере-использования конкретного типа отображения слайдера из UI-kit проекта.
Папки icons и illustrations
Только для Next.js, т.к. как ни странно, пока что в него нельзя импортировать иконки как компоненты напрямую из svg (в то время как в React можно). Как понятно из названий папок, в них лежат JSX-компоненты с svg-кодом. Для иллюстраций отдельная папка, чтобы иконки не перемешивались с svg-иллюстрациями.
Папка cards
В ней содержатся компоненты отображающие некоторое количество информации об какой либо отдельной сущности. Чаще всего когда эти компоненты используются в частях проекта, они выводятся циклом через map. Как пример - карточка товара в списке товаров интернет-магазина, элемент "отзыв" из списка отзывов, баннеры (не являющиеся слайдерами), и так далее.
Примеры компонентов, к-е должны находиться в папке cards
Папка ui
UI расшифровывается как user interface. В данной папке будут располагаться компоненты пользовательского интерфейса не попадающие ни под одну из категорий, описанных выше. Например header, footer, хлебные крошки, пагинация, и т.д.
Очень важно прежде чем создавать папку компонента в папке ui, проверить, не попадает ли он под категории описанные выше, и если попадает - создать его именно в необходимой папке.
Отлично, файловая структура для проекта готова!
Благодаря данному подходу мы добились чёткой и понятной структуры папок, в которой легко найти любой нужный файл, благодаря тому, что ни в одной из папок не будет слишком много папок или файлов. Сразу заходим в папки по смыслу, и находим нужный файл.
Ещё несколько рекомендаций:
Создавая папки для самих компонентов, называйте их по смыслу. Экспериментируя, я пробовал называть папки/файлы используяВерблюжийСтиль а также используя_нижнее_подчёркивание, и обнаружил, что наиболее приятным для восприятия является подход, где в названии файла/папки вместо.пробелов.используются.точки
Я рекомендую создавать для каждого компонента папку, где в index.jsx (или index.tsx) будет храниться код компонента, а так же в этой же папке будет располагаться отдельный файл со стилями компонента (какой бы способ вы ни использовали - хоть scss, хоть styled).
Не создавайте несколько компонентов в одном файле, и тем более компонент внутри компонента. Первое не наглядно, а второе так и вовсе вредит оптимизации.
При этом старайтесь каждую часть интерфейса выделять в отдельный компонент, и использовать его. Т.к. одна из основных прелестей React/Next, о которых мы говорим - модульный подход.
Код станет значительно нагляднее, если не пихать львиную долю вёрстки в один файл (хоть и это тоже будет работать), а собирать отдельные части в отдельные "пазлы", и уже из этих "пазлов" собирать общую картину. И каждый "пазл" может сам состоять из нескольких "пазлов".
Проще говоря - создавайте компоненты из других компонентов, созданных в свою очередь из других компонентов, которые вы создали. Каждая часть которую можно изолировать в компонент, должна быть изолирована в компонент.
Вот к примеру скриншот с кода одной из страниц моего сайта, представляющей из себя достаточно длинный лэндинг:
Представьте, как выглядела бы страница, если бы JSX-код всех секций находился не в отдельных компонентах, а прямо на этой странице? Это была бы полная жуть, в которой невозможно ориентироваться. А тут смотрим - и сразу понятно, где какая секция. Можно перейти в неё прямо из этого файла, и отредактировать при необходимости.
Не ленитесь создать и заполнить файл readme.md в корне проекта!
Существует куча редакторов markdown, в которых можно создать оформленный текст, без знаний разметки md. В этом файле опишите структуру проекта, чтобы другим программистам (и в т.ч. вам) было проще ориентироваться в файловой структуре проекта. Также опишите в нём, как разворачивать проект в первый раз, как разворачивать для разработки и для продакшена. Прикрепите ссылки на материалы проекта (дизайн в figma, документация к API и так далее.
Веб-сервисы для хостинга репозиториев Git-а (GitHub, GitLab, и т.д.) понимают markdown, и на странице вашего проекта, под списком файлов, будет инструкция со всеми ссылками.
Это очень классно и удобно, оценят все - и коллеги по команде, и заказчики, и даже если вы работаете в одиночку над собственным проектом, этот файл будет вам полезен.
Желаю удачи в разработке проектов!
Расскажите в комментариях, какой способ организации папок и файлов вы используете в своих проектах, а также удалось ли взять из этой статьи какие либо приёмы на вооружение. Если есть идеи как ещё можно усовершенствовать данную структуру - тоже пишите. Скорее всего идеи по улучшению появятся со временем и у меня самого, в этом случае я буду дополнять статью.
Комментарии (10)
OneKek
23.06.2024 21:42+2Используете ли вы в одном проекте tailwind и scss?
Rikkster Автор
23.06.2024 21:42Да, но поскольку я использую для вёрстки adaptivepx.ru, я создаю кастомный файл tailwind.scss где размеры указаны в адаптивных пикселях, и есть только те атомарные стили, которые я использую в проекте. Т.е. я использую идею tailwind, но не саму библиотеку.
novoselov
23.06.2024 21:42+6К примеру это может быть компонент carcas - общая обёртка для всех страниц
Вот такое именование вы выработали за 10+ лет опыта коммерческой разработки?
artptr86
Что же в этой структуре от MVC?
Ну камон, не Гит же, а Гитхаб или Гитлаб, хотя бы.
Rikkster Автор
То, что мы не городим в одном файле и всю связанную вёрстку и всю связанную логику, конечно же. MVC в названии к тому, что речь пойдёт не про какой нибудь FSD к примеру.
Все GIT-производные, а их гораздо больше, GitVerce например есть от отечественного производителя. Суть-то понятна, что я имею в виду - вряд ли речь идёт про консоль.
artptr86
MVC в названии подразумевает архитектурное разделение на модель, вид и контроллер. Были даже когда-то фронтендные фреймворки, основанные на таком паттерне, например, Backbone. Просто так употреблять эту аббревиатуру для отличия от FSD — неправильно. Точно так же, как неправильно называть произвольный сервис хранения исходного кода "гитом". Тем более, что вы учите других. А то ведь в Интернете известны примеры типа «Язык Джаваскрипт, для простоты называемый Джавой».
Rikkster Автор
Именно об этом и идёт речь в статье, а именно:
Модель - глобальный и локальный стейт а также хуки (хранят модель данных, отображаемых на странице). Глобальный стейт по статье хранится в папке store
Вид - компоненты React являются представлением, т.к. отвечают за отображение данных и реагирование на действия пользователей. По статье хранятся в папке React
Контроллер - JS-логика как данные получаются, обрабатываются и обновляются. По статье подобные функции находятся в папке scripts, так же контроллерами можно считать экшены, по статье хранящиеся в store/actions
Я вижу не одного вас это сильно задело, ну так то вы в данном случае правы, отредактировал статью
artptr86
Вообще-то нет, MVC — вполне себе конкретный паттерн. Иначе тогда вообще размывается разница между MVC, MVP, MVVM и прочими подобными паттернами, а за разделение ответственности у нас и так отвечает S в SOLID.
Rikkster Автор
Я конкретно ответил каким образом реализуется MVC в моём примере. Аргументируйте, если не согласны.