Файлы 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 имеет достаточные возможности рефакторинга для их обработки, до такой степени, что недостатки незначительны.