Как написать модуль ES, имеющий как экспорт по умолчанию, так и именованный?

Я хочу сделать свой модуль ES импортируемым в обоих следующих стилях:

import * as mylib from "./mylib.mjs";
import mylib from "./mylib.mjs";

Затем я написал mylib.mjs в следующем стиле:

export function foo(){
}
export function bar(){
}
export function baz(){
}
// ... and many export functions...(1)
export default {foo, bar, baz, /* ... and many function names...(2) */};

Но мне всегда приходится беспокоиться о том, что некоторые имена отсутствуют в export default(2). Если добавляется новый export functions(1), мне придется добавить его также в function names(2). Я часто об этом забываю.

В CommonJS использование exports делает это более разумным. Есть ли какая-либо переменная, эквивалентная exports в модуле ES?

exports.foo=function () {
};
exports.bar=function () {
};
exports.baz=function () {
};
exports.default=exports;// No need to change here when function export is added.

«Я хочу, чтобы мой ES-модуль можно было импортировать в обоих следующих стилях» — у вас есть для этого веская причина? Кажется, это намного хуже, чем просто остановиться на import * as mylib.

Ry- 07.05.2024 04:14

То, что вы пытаетесь сделать, для меня - это запах кода, а для меня - указание на код низкого качества, написанный не-js-программистом. ИМХО правильный ответ - не делать этого

slebetman 07.05.2024 04:14

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

morganney 07.05.2024 06:23

использование import mylib from "./mylib.mjs" вместо import * as mylib from "./mylib.mjs" выглядит нехорошо, сбивает с толку, DRY/SSOT в некоторой степени нарушен

Alexander Nenashev 07.05.2024 10:53

Я бы сказал, что импорт пространства имен (import * as) — это антишаблон. Почему, потому что модули es могут импортировать модули cjs, а узел пытается определить именованный экспорт , но этот процесс не идеален, поэтому для лучшей совместимости рекомендуется использовать подход к импорту по умолчанию. Например, namespace.foo может выдать ссылочную ошибку, если foo не удалось обнаружить с помощью эвристики. Руководство по стилю airbnb также не рекомендует этого делать. Лучше быть конкретным и просто использовать именованный экспорт.

morganney 07.05.2024 15:10

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

morganney 07.05.2024 15:16
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
6
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я бы не советовал этого делать, так как считаю, что файлы стволов — это антишаблон, и лучше иметь один способ загрузки ваших модулей, но что-то, что вы могли бы сделать, чтобы приблизиться к тому, что вы хотите, — это организовать свой проект следующим образом: этот:

.
└── src/
    ├── mylib/
    │   └── mod.mjs
    ├── mylib.mjs
    └── consumer.mjs

mylib/mod.mjs

export function foo(){
}
export function bar(){
}
export function baz(){
}

mylib.mjs

export * from './mylib/mod.mjs'
export * as default from './mylib/mod.mjs'

потребитель.mjs

import * as mylibNs from './mylib.mjs'
import mylib from './mylib.mjs'

Для управления экспортом требуется дополнительный файл, но вам не придется обновлять экспортированные имена в нескольких местах.

Конечно, если вас устраивают циклические ссылки в ваших модулях, вы можете иметь только один файл вроде этого:

mylib.mjs

export function foo() {
}
export function bar() {
}
export function baz() {
}

export * as default from './mylib.mjs'

Оно будет использоваться так же, как и раньше, но свойство default будет ссылкой на сам модуль, т. е. mylib.default === mylib.

Это было протестировано с использованием Node.js v20.12.0.

Другие вопросы по теме