Переход от std / esm к поддержке esm в узле V14 - не удается найти именованный импорт - отлично работает с std / esm - PullRequest
1 голос
/ 29 мая 2020

В первую очередь за год + Я написал весь свой код, используя esm, а с пакетом std / esm я могу легко использовать зависимые пакеты с cjs без проблем без использования babel.

В nodejs V14 смешанный esm / cjs поддержка теперь включена без флага, и проект std / esm, похоже, сворачивается, поэтому я подумал, что должен попытаться выполнить миграцию, чтобы увидеть, что проблемы могут быть. Я нашел его.

https://github.com/standard-things/esm

https://nodejs.org/api/esm.html#esm_ecmascript_modules

Проблема, с которой я столкнулся, заключается в том, что в отличие от std / esm the esm / cjs поддержка, теперь включенная в V14 nodejs, нарушает именованный импорт (я предполагаю, что общий js экспорт модулей) , который отлично работал с std / esm.

Возьмем, например, https://github.com/sindresorhus/make-dir/blob/978bee9186bf0c41640ed21567921daf8c303225/index.js#L106

в качестве пакетов используется cjs. Вот экспорт

module.exports.sync = (input, options) => {
    checkPath(input);
    options = processOptions(options);

Использование "type":"module" в моем пакете. json. В моем коде есть import import { sync as mkdir } from 'make-dir' , который отлично работает с использованием std / esm . Но при использовании nodejs 14 он говорит, что не может найти именованный экспорт sync. **

import { sync as mkdir } from 'make-dir'
         ^^^^
SyntaxError: The requested module 'make-dir' does not provide an export named 'sync'

Я застрял здесь? Мне нужно оставаться с std / esm? (но похоже, что проект уже завершен) Я не могу / не должен go использовать всю мою базу кода, вмещающую cjs модули с

import mk from 'make-dir'
const mkdir = mk.sync

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

https://github.com/dkebler/core-esm-named-import-error

Во всяком случае, предполагалось, что esm в версии 14 должен был стать заменой использования std / esm. Видимо нет :(.

1 Ответ

2 голосов
/ 11 июня 2020

Техническая причина, по которой Node.js поддерживает экспорт по умолчанию только для сценариев CJS, заключается в том, что ESM import имеет значение stati c (анализируется перед выполнением модуля) и CJS module.exports is Dynami c (вы можете сделать что-нибудь сумасшедшее, например module.exports[Date.now()] = 0, и это сойдет с рук). Единственный способ узнать наверняка, какие «имена» экспортирует модуль CJS, - это проанализировать и выполнить его, что, кажется, несовместимо со спецификациями ES6.

Некоторые сборщики (например, std / esm ) используйте регулярное выражение в коде модулей CJS, чтобы найти экземпляры module.exports.<named export> =, и используйте его для определения именованного списка экспорта для модуля. Обратной стороной этого метода является то, что вы не найдете всех экспортов, а анализ больших файлов может потребовать очень много памяти. Также это означает двойной синтаксический анализ модулей CJS, и хотя снижение производительности может быть приемлемым для сборщиков, для среды выполнения, такой как Node.js, оно того не стоит.

Итак, что можно сделать? Вот что я делал, когда сталкивался с этой проблемой:

  • открытые проблемы в репозитории пакета, чтобы запросить версию ESM. Многие пакеты сегодня переносят модули ES6 / TypeScript в CJS при публикации в NPM, они могут легко распространять версию ESM вместе с CJS одной .
  • Используйте https://github.com/mgechev/is-esm в своих зависимостях, чтобы определить, что будет поддерживать именованный импорт.
  • Используйте https://github.com/ds300/patch-package для преобразования CJS пакетов в ESM.
  • Продолжайте использовать std / esm или бандлер. Пока это работает для вас, это все еще действительный вариант.
...