Файлы Index.js — это симпатичная функция, которую придумал Райан Даль, когда разрабатывал Node.js. Хотя он официально сожалеет о них, я думаю, что они превратились в полезный инструмент для структурирования кода. В этом посте я постараюсь сформулировать правила, которые я для себя вывел относительно них.

По сути,файлы индексов служат одной из двух целей: в качестве инкапсуляции или в качестве пространства имен. Следствием этого является то, что индексные файлы действуют как ограждения для импорта — я избегаю импорта чего-либо из подпапки папки, содержащей индексный файл.

Инкапсуляция

Если для инкапсуляции используется индексный файл, он должен содержать экспорт по умолчанию для основного объекта (класса, компонента, функции и т. д.) в папке. Он также может содержать несколько экспортов имен для связанных, «вторичных» элементов. Это полезно, когда вы хотите скрыть детали реализации модуля и предоставить доступ только к одному интерфейсу. Например, рассмотрим следующую структуру папок:

src
└── TopBar
    ├── index.js
    ├── TopBar.js
    ├── DropDown.js
    └── SearchBox.js

В этом случае папка TopBar содержит реализацию компонента верхней панели, включая несколько подкомпонентов. Индексный файл повторно экспортирует компонент в TopBar.js:

// index.js
export { default } from './TopBar';

Чтобы использовать компонент, вы должны импортировать экспорт по умолчанию из папки TopBar:

import TopBar from './TopBar';

Пространство имен

Если индексный файл используется в качестве пространства имен, он должен содержать кучу именованных экспортов для всего в папке. Раньше я делал это часто, но на самом деле я перестал это делать в пользу того, чтобы просто иметь имя папки в импорте. Тем не менее, может быть полезно сгруппировать связанные объекты под одним идентификатором, если они кажутся особенно сильно связанными.

Например, рассмотрим следующую структуру папок:

src
└── shared-components
    ├── LoadingButton.jsx
    ├── Spinner.jsx
    └── ModalDialog
        ├── ModalDialog.jsx
        ├── index.js
        └── Overlay.jsx
    ├── Chevron.jsx
    └── index.js

В этом случае папка shared-components содержит четыре компонента. Файл index.js в

export { default as LoadingButton } from './LoadingButton';
export { default as Spinner } from './Spinner';
export { default as ModalDialog } from './ModalDialog';
export { default as Chevron } from './Chevron';

Это заставляет shared-components работать как своего рода пакет, из которого вы можете импортировать компоненты. Преимущество импорта компонентов из соответствующих подкаталогов невелико, но может быть на ваше усмотрение.

Импорт из подпапок

Если в папке есть индексный файл, я считаю это ограждением, которое должно помешать мне импортировать что-либо из подпапок. Теперь файлы, которые находятся в папке или подпапке сами, могут импортировать вещи, вы просто не должны пересекать границу, так сказать. Это то, для чего я хочу создать правило линтера, потому что оно может применяться автоматически, но пока я отслеживаю его вручную.

Эмерджентный дизайн

Оба варианта использования хорошо подходят для эмерджентного дизайна.

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

При использовании для пространств имен это хороший первый шаг для группировки связанного кода перед его перемещением в отдельный пакет либо в вашем монорепозитории с использованием рабочих пространств, либо на всем пути к NPM, в зависимости от того, насколько универсальным он станет.

.. экспорт по умолчанию??

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