Почему не стоит использовать
export default в своей кодовой базе?- export default позволяет экспортировать анонимные функции:
Если где-либо будет выброшена ошибка, в ее stack trace все анонимные функции, через которые она прошла, будут помечены записью
В React, если таким способом экспортировать компонент, он не получит имени в дереве компонентов в
Также, такое содержимое мы не сможем найти через поиск по коду в IDE, так как оно попросту не присвоено ни в какую переменную (на уровне исходного кода), а следовательно не имеет имени.
Обычно авто-импорты в редакторах/IDE предлагают импортировать такие функции по имени файла.
Например, для импорта значения дефолтного экспорта из файла
Тем не менее, при переименовании такого файла, имя у существующих импортов заменено не будет, при этом для следующих импортов будет предложено уже новое имя в соответствии с новым именем файла.
Таким незаметным образом в коде могут появиться импорты одного и того же значения под разными именами, и возникнет ситуация, описанная в следующем пункте.
- Импорт такого значения беспрепятственно позволяет указать ему любое имя:
Это усиливает влияние человеческого фактора на код, особенно когда у кого-нибудь из разработчиков по какой-то причине нет авто-импорта в редакторе/IDE.
Кто-угодно сможет легко импортировать содержимое под другим именем, что сильно усложнит поиск мест, в которых это содержимое используется.
При использовании именованного экспорта, в любом случае придется указать изначальное имя переменной.
Даже если надо импортировать ее под другим именем:
Именованные экспорты упрощают поиск по проекту и рефакторинг.
- С дефолтными экспортами проблематично делать реэкспорт, например в UI слое:
Это усложняет код и добавляет нежелаемый бойлерплейт.
- Код становится менее консистентным:
Код с двумя видами экспортов менее единообразен и сложен в понимании. К тому же, дефолтные экспорты часто требуют иного подхода, например, при реэкспортах.
При использовании именованных экспортов все кейсы решаются одинаково просто.
Если где-либо будет выброшена ошибка, в ее stack trace все анонимные функции, через которые она прошла, будут помечены записью
at <anonymous>, что усложнит поиск места возникновения данной ошибки.В React, если таким способом экспортировать компонент, он не получит имени в дереве компонентов в
React DevTools, следовательно будет сложнее увидеть полную картину и понять, с каким компонентом мы имеем дело.Также, такое содержимое мы не сможем найти через поиск по коду в IDE, так как оно попросту не присвоено ни в какую переменную (на уровне исходного кода), а следовательно не имеет имени.
Обычно авто-импорты в редакторах/IDE предлагают импортировать такие функции по имени файла.
Например, для импорта значения дефолтного экспорта из файла
some-thing.ts будет предложено имя someThing для функции и SomeThing для класса.Тем не менее, при переименовании такого файла, имя у существующих импортов заменено не будет, при этом для следующих импортов будет предложено уже новое имя в соответствии с новым именем файла.
Таким незаметным образом в коде могут появиться импорты одного и того же значения под разными именами, и возникнет ситуация, описанная в следующем пункте.
- Импорт такого значения беспрепятственно позволяет указать ему любое имя:
/* component.js */
const Component = () => { ... }
export default Component
/* other-file.js */
import MyComponent from 'component.js'
import OtherComponent from 'component.js' // или так?
import Something from 'component.js' // а может даже так?Это усиливает влияние человеческого фактора на код, особенно когда у кого-нибудь из разработчиков по какой-то причине нет авто-импорта в редакторе/IDE.
Кто-угодно сможет легко импортировать содержимое под другим именем, что сильно усложнит поиск мест, в которых это содержимое используется.
При использовании именованного экспорта, в любом случае придется указать изначальное имя переменной.
Даже если надо импортировать ее под другим именем:
import { Component as Something } from 'component.js'Именованные экспорты упрощают поиск по проекту и рефакторинг.
- С дефолтными экспортами проблематично делать реэкспорт, например в UI слое:
/* ui/button.js */
export default Button() {}
/* ui/link.js */
export default Link() {}
/* ui/index.js */
export * from './button'
export * from './link'
// -> Error: multiple default exportsЭто усложняет код и добавляет нежелаемый бойлерплейт.
- Код становится менее консистентным:
Код с двумя видами экспортов менее единообразен и сложен в понимании. К тому же, дефолтные экспорты часто требуют иного подхода, например, при реэкспортах.
При использовании именованных экспортов все кейсы решаются одинаково просто.
👍23❤1👎1
Исключения:
- Экспорт основного содержимого библиотеки.
(например, чтобы можно было сделать так:
Тем не менее, обычно это все еще нежелательно.
- Некоторые модули, которые в соответствии с архитектурой фреймворка должны быть экспортированы по умолчанию.
(например, компоненты страниц в Next.js)
- Различные конфиги и все остальное, чьими потребителями является программный код, а не разработчики.
Это позволяет упростить код внутри библиотеки - она может просто сделать
- Экспорт основного содержимого библиотеки.
(например, чтобы можно было сделать так:
import React from 'react')Тем не менее, обычно это все еще нежелательно.
- Некоторые модули, которые в соответствии с архитектурой фреймворка должны быть экспортированы по умолчанию.
(например, компоненты страниц в Next.js)
- Различные конфиги и все остальное, чьими потребителями является программный код, а не разработчики.
Это позволяет упростить код внутри библиотеки - она может просто сделать
require файла и получить необходимый объект, без обращения к полю.Дополнительная информация:
- Google в своем стайлгайде предлагает использовать именованные экспорты:
https://google.github.io/styleguide/jsguide.html#es-module-exports
- В Gitlab перешли на именованные экспорты:
https://gitlab.com/gitlab-org/frontend/rfcs/issues/20
- Google в своем стайлгайде предлагает использовать именованные экспорты:
https://google.github.io/styleguide/jsguide.html#es-module-exports
- В Gitlab перешли на именованные экспорты:
https://gitlab.com/gitlab-org/frontend/rfcs/issues/20
Лайфхак для использования
Использование:
Кстати, WebStorm при рефакторинге с переименованием даже подтягивает новое имя компонента во второй аргумент =)
React.lazy с именованными экспортами
export const namedLazy = <T extends Record<string, any>>(
loader: () => Promise<T>,
name: keyof T,
) =>
React.lazy(async () => {
const module = await loader()
return { default: module[name] }
})Использование:
const Component = namedLazy(() => import('./component'), 'ComponentName')Кстати, WebStorm при рефакторинге с переименованием даже подтягивает новое имя компонента во второй аргумент =)
🔥31👍5👎1