Проблемы экспорта по умолчанию в модулях JavaScript

Источник: «Why to Avoid Default Exports in JavaScript Modules»
Модули JavaScript — способ организации кода в многократно используемые компоненты, используемые совместно в разных файлах и проектах. Модули можно импортировать и экспортировать с помощью двух различных методов: экспорта по умолчанию и именованного экспорта. Рассмотрим экспорт по умолчанию и причины, по которым следует избегать его использования в модулях JavaScript.

Что такое экспорт по умолчанию в модулях JavaScript

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

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

// math.js
export default function subtract(a, b) {
return a - b;
}

В этом примере функция subtract является экспортом по умолчанию для модуля math. Её можно импортировать с любым именем в другой файл, например, так:

// app.js
import add from './math.js';
const result = add(2, 2); // returns 0

Обратите внимание, что функция вычитания была импортирована как multiply (умножение). Это возможно потому, что экспортируемые по умолчанию функции можно импортировать с любым именем. Это может привести к путанице и усложнить сопровождение кода по мере роста кодовой базы.

Проблема с экспортом по умолчанию

Экспорт по умолчанию не обнаруживается IDE

Основная проблема экспорта по умолчанию заключается в том, что его нельзя обнаружить.

При импорте модуля, имеющего только именованные экспорты, IDE показывает список доступных экспортов, которые могут быть использованы в коде. Однако с экспортом по умолчанию это невозможно, поскольку он не имеет имени. Это означает, что разработчики могут не знать, что у модуля есть экспорт по умолчанию, или не знать, как он называется. В результате может возникнуть путаница, и модуль станет сложнее использовать.

VSCode показывает список доступных экспортов
VSCode показывает список доступных экспортов

Экспорт по умолчанию неудобен при рефакторинге

Другая проблема с экспортом по умолчанию заключается в том, что он неудобен в плане рефакторинга.

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

Именованный экспорт можно автоматически переименовать
Именованный экспорт можно автоматически переименовать

Экспорт по умолчанию — кошмар именования

Экспорт по умолчанию также может создать проблемы с именованием. Поскольку его можно импортировать с любым именем, разные разработчики могут использовать разные названия для одного и того же экспорта по умолчанию. Это может привести к несогласованности и затруднить сопровождение кода по мере роста кодовой базы.

Напротив, именованные экспорты обеспечивают чёткое и последовательное соглашение об именовании, что значительно упрощает понимание и поддержку кода.

Альтернативы экспорта по умолчанию

Именованный экспорт

Именованные экспорты — хорошая альтернатива экспорту по умолчанию. С помощью именованных экспортов можно экспортировать несколько значений из модуля и дать каждому из них чёткое и последовательное имя. Это облегчает другим разработчикам понимание и использование кода.

Пример модуля, экспортирующего две именованные функции:

// math.js
export function add(a, b) {
return a + b;
}

export function subtract(a, b) {
return a - b;
}

В данном примере экспортируются две именованные функции, add и subtract. Их можно импортировать в другой файл следующим образом:

// app.js
import { add, subtract } from './math';

const sum = add(2, 2); // returns 4
const difference = subtract(2, 2); // returns 0

Обратите внимание, что функции импортируются с использованием их имён, что облегчает понимание и сопровождение кода.

Обёртка для экспорта по умолчанию

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

// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// math-wrapper.js

// Выбираем, что экспортировать
export { add, subtract } from './math';

// ИЛИ экспортируем целиком
export * as default from './math';

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

Использование обёртки для экспорта по умолчанию
Использование обёртки для экспорта по умолчанию

Это также позволяет сохранить чёткое и последовательное именование, избежав проблем с экспортом по умолчанию.

Необходимость экспорта по умолчанию

Не существует абсолютов во всём, и в некоторых случаях экспорт по умолчанию необходим. Например, при инкапсуляции обычных компонентов:

ls ./components
Row.jsx Form Upload.jsx
Select Alert.jsx Skeleton
...

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

Рекомендуется называть экспортируемый по умолчанию компонент в соответствии с именем файла и именем компонента в файле. Это минимизирует недоразумения и ошибки и позволит изменять имена IDE.

// app.js
import Row from './Row.jsx';

import Select from "./Select"

Кроме того, рекомендуется использовать index.js в папке components, для объединения компонентов и использования именованных экспортов:

// components/index.js
export { default as Row } from './Row.jsx';
export { default as Select } from './Select';
// app.js
import { Row, Select } from "./components";

Другие лучшие практики

Помимо рассмотренных альтернативных вариантов, существуют и другие лучшие практики, которым стоит следовать, чтобы улучшить сопровождаемость кода:

Заключение

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

Комментарии


Дополнительные материалы

Предыдущая Статья

Совет по безопасности: Параметризуйте имена параметров!

Следующая Статья

Разница между export default xxx и export {xxx as default}