Skip to content

Latest commit

 

History

History
259 lines (188 loc) · 12 KB

rifs.md

File metadata and controls

259 lines (188 loc) · 12 KB

RIFS

React Idiomatic File Structure

Преамбула

Проблематика

Данная концепция представляет собой набор сущностей и приёмов, позволяющих достичь максимальной простоты в работе с файловой структурой, подкреплённой принципами интуитивности, расширяемости и модульности.

Основная проблема, решаемая RIFS, - нивелирование человеческого индивидуального фактора в работе с React-приложением. Многое нижеизложенное позаимствовано из фреймворка AngularJS, перенося некоторые подходы на реалии работы в экосистеме React.

Цель

Целью этого проекта является достижение чувства "until it feels right".

Методология

Для достижения цели будет использовано разделение на узлы (nodes), сущности (entities), типы (types) и свойства (features). Каждый элемент должен следовать принципу единой ответственности.

Глава 1. Наименование

Принцип наименования всегда един - использование т.н. kebab-case (иногда dash-case) с разделением через точку. Для примера возьмём list-item.component.tsx. В данном случае list-item является названием узла, component - типом узла, tsx - расширением (отображающим используемый в данном узле язык).

Глава 2. Узлы

Узел (node) - файл, папка, или группа файлов/папок, собираемые в единое свойство приложения. Узел несёт ответственность за свою часть функциональности и может быть частью других узлов, составляя с ними более сложные структуры.

В файловой системе узел выражается через корневую часть названия файла или папки.

Глава 3. Сущности

Сущность (entity) - узел, представленный в виде файла. Является ключевым в своей папке и может представлять одну из приведённых моделей:

  • Компонéнт (component)
  • Контéкст (context)
  • Сéрвис (service)

Все сущности тем или иным образом взаимодействуют с API React, имея свою задачу и зону ответственности.

Компонент

Компонентом является сущность, работающая с DOM-деревом и напрямую взаимодействующая с пользователем в виде интерфейса (view). Компонент может иметь собственное состояние (state), выражаемое через хуки, и получать зависимости через пропсы (props) или через контекст.

export const ListItem: FC<ListItemProps> = ({ index }) => {
  /* любая логика и состояние
  возврат DOM элементов */
};

Контекст

Контекст отвечает за общую логику сродных узлов и выступает поставщиком (provider) пропсов. С помощью контекста достигается принцип инверсии управления, благодаря которому нижестоящие узлы получают доступ к зависимостям извне, что позволяет лучше контролировать поток данных и тестировать эти узлы.

Контекст включает в себя две составные части - поставщик и хук. Поставщик должен оборачиваться над всеми заинтересованными узлами снаружи, давая им доступ к данным. Хук забирает на себя роль получателя (consumer), подписывающего узел на изменения состояния.

const PathContext = createContext<PathModel | undefined>();

const Path: FC = ({ children }) => {
  return (
    <PathContext.Provider
      value={
        {
          /* */
        }
      }
    >
      {children}
    </PathContext.Provider>
  );
};

export const usePath = (): PathModel => {
  const context = useContext(Path);

  if (context === undefined) {
    throw new ReferenceError('Use Path inside of its provider.');
  }

  return context;
};

export default Path;

Сервис

Сервис является частным случаем контекста. Основным отличием является то, что сервис должен быть инстанциирован единожды. Например, провайдер темы приложения.

Наиболее частой областью применения сервиса является выделение единого куска логики, поставляемого в необходимые места.

Чем уже область применения сервиса - тем лучше.

Глава 4. Типы

Тип узла более узко определяет его назначение. Сущности также являются и типами, собирающими в себе другие типы. Также, узел может не иметь явно заданного типа, что относится к, например, утилитным функциям или хукам. Их тип подразумевается из места их расположения (папки utils/ или hooks/).

К типам относятся:

  • Стили (styles)
  • Пропсы (props)
  • Конфигурация (config)
  • Модуль (module)
  • Тесты (spec)

Стили

list-item.styles.scss

Стили напрямую относятся к компонентам и являются источником стилизации для них.

Пропсы

list-item.props.d.ts

Для описания пропсов компонента используется специальный тип props.

Всё, что к пропсам не относится, должно быть выделено в отдельный узел entity, который должен собирать в себе модели и интерфейсы, дополняющие модель компонента.

Конфигурация

requests.config.ts

В конфигах собраны данные, необходимые в настройках работы узлов (чаще всего приложения). К таким, например, относятся конфиги запросов или отдельных сервисов.

Модуль

routes.module.ts

Модулем может являться выделенный группа объектов или объект, содержащий в себе статические данные, и который не зависит от происходящих вокруг него процессов. Например, модулем может являться файл, собирающий в себе массив роутов и отдающий ответственность за их поведение и расположение компоненту.

Тесты

list-item.spec.ts

Каждый узел, в идеале, должен быть покрыт unit-тестами, вынесенными в файл с типом spec.

Глава 5. Свойства

Свойство (feature ) - высокоуровневый самостооятельный блок, из которого собирается всё приложение. В него входят все вышеописанные узлы, которые также могут являться свойствами.

core/

В приложении обязательно должно быть core-свойство, который содержит в себе компонент приложения app и дополнительные глобальные свойства, такие как theme или store.

shared/

Также, в приложении может присутствовать shared-свойство, собирающее в себе все общие и переиспользуемые узлы и типы.

assets/

Отдельным блоком стоит папка assets, поставляющая в приложение и пользователю все, не связанные с функциональностью элементы. Например, assets/images, assets/fonts.

Глава 6. Модули

Основным свойством приложения являются его модули. В данном контексте модули представляют собой основные строительные блоки приложения.

Говоря о React-приложении, под модулями мы подразумеваем его страницы. Каждый модуль (страница), как и сервис, должен иметь единый инстанс и являться родителем для всех нижестоящих компонентов.

Модуль также должен получать свои зависимости извне, для чего все его сервисы должны быть инстанциированы в компоненте app, который также принимает на себя функцию Service Locator.

Глава 7. index

Каждая папка (кроме корневых узлов внутри src) должна иметь файл index.ts, экспортирующий все необходимые узлы из неё. В контексте экосистемы NodeJS index.ts является корневым модулем любого узла, через который происходит взаимодействие узлов друг с другом.

Глава 8. Итоговая структура

В итоге, наше приложение может иметь следующую структуру файлов:

  • src/
    • assets/
      • images/
      • icons/
      • fonts/
      • styles/
    • core/
      • app/
      • theme/
      • store/
      • routes.module.ts
    • modules/ (pages/)
      • main/
      • about/
        • contacts/
        • form/
          • form-validator/
            • form-validator.service.tsx
            • form-validator.spec.tsx
            • index.ts
          • form.component.tsx
          • form.styles.ts
          • index.ts
        • about.component.tsx
        • about.styles.tsx
        • index.ts
    • shared/
      • components/
      • entity/
      • services/
      • utils/
      • hooks/