Эта статья подготовлена ​​командой разработчиков модуля Node.js.

Еще в 2017 году в Node.js 8.9.0 была реализована экспериментальная поддержка модулей ECMAScript, известных своими операторами import и export. Эта поддержка стояла за флагом --experimental-modules.

С тех пор многое произошло. Все основные браузеры теперь поддерживают модули ECMAScript (модули ES) через ‹script type =” module ”›. Появились различные проекты, чтобы сделать пакеты npm с исходными кодами модулей ES доступными для использования в браузерах через ‹script type =” module ”›. Поддержка карт импорта, которые выводят в браузеры имена пакетов в стиле Node.js в операторах import, приходит в Chrome.

Весь этот прогресс в направлении внедрения модулей ES повысил актуальность для Node.js поддержки модулей ES. Теперь, когда есть другие среды выполнения и среды, в которых используются модули ES, как никогда важно, чтобы Node.js поддерживал этот стандарт JavaScript.

Первоначальная поддержка модулей ES в Node.js оставалась в экспериментальном состоянии, чтобы у сообщества было время высказать свое мнение по этому проекту. Команда модулей была сформирована, чтобы реагировать на эту обратную связь и предоставлять первоклассную поддержку ES-модулей в Node.js. Это привело к новой реализации для поддержки модулей ES, и мы рады сообщить, что она будет поставляться как часть Node.js 12. Она заменит старую реализацию --experimental-modules, лежащую в основе. тот же флаг. Мы надеемся, что эта новая реализация решит многие проблемы сообщества и может поставляться как часть собственно Node.js без флага до того, как Node.js 12 достигнет статуса LTS в октябре 2019 года.

Что в --experimental-modules

Как и в предыдущей версии, этот новый --experimental-modules добавляет в Node.js поддержку следующего:

  • Операторы импорта ES2015 могут ссылаться на файлы JavaScript, которые сами написаны с использованием синтаксиса модуля ES. На файлы можно ссылаться как на относительные URL-адреса ('./file.mjs'), абсолютные URL-адреса file: // ('file: /// opt / app /file.mjs '), имена пакетов (' es-module-package ') или пути внутри пакетов (' es-module-package / lib / file.mjs ' ).
  • Операторы import, которые ссылаются на файлы модуля ES, могут указывать как экспорт по умолчанию (import _ from 'es-module-package'), так и именованный экспорт (import {shuffle} from 'es-module-package') и экспорт пространства имен (import * as fs from 'fs'). Все встроенные пакеты Node.js, такие как fs и path, поддерживают все три типа экспорта.
  • Операторы import, которые ссылаются на файлы CommonJS (весь текущий код JavaScript, написанный для Node.js, с использованием require и module.exports), могут использовать экспорт CommonJS по умолчанию (import _ from 'commonjs-package ') только. Эта работа еще не завершена, и в будущем она может измениться.
  • Операторы экспорта в файлах модуля ES могут указывать как экспорт по умолчанию, так и именованный экспорт для ссылок на операторы импорта.
  • Динамические выражения import () могут использоваться для импорта модулей ES из файлов модулей CommonJS или ES. Обратите внимание, что import () возвращает обещание.
  • import.meta.url предоставляет абсолютный URL-адрес текущего файла модуля ES.
  • Можно написать загрузчики для изменения поведения среды выполнения Node.js по отношению к модулям ES. Эта работа все еще продолжается.
  • Node.js можно запустить с файлом модуля ES в качестве начальной точки входа в программу.
  • Файлы, загружаемые как модули ES, загружаются в строгом режиме, который в CommonJS требует добавления ‘use strict’ ​​; в начало каждого файла.
  • Файлы, заканчивающиеся на .mjs, явно обрабатываются как модули ES в операторах import и при запуске с помощью команды node.

А новая версия --experimental-modules добавляет:

синтаксис импорта и экспорта в файлах .js

Мы слышали очень сильную обратную связь о том, что Node.js должен предоставить способ использования синтаксиса import и export в .js файлы.

Новый --experimental-modules предоставляет два способа: для файлов - поле «тип» в package.json; а для ввода с помощью --eval, --print или STDIN - флаг --input-type.

package.json поле «тип»

Добавьте «type»: «module» в package.json вашего проекта, и Node.js обработает все файлы .js в вашем проект как модули ES.

Если некоторые из файлов вашего проекта используют CommonJS и вы не можете преобразовать весь проект сразу, вы можете либо переименовать эти файлы, чтобы использовать расширение .cjs, либо поместить их в подпапку, содержащую package.json на {«type»: «commonjs»}, при котором все файлы .js обрабатываются как CommonJS.

Для любого файла, который Node.js пытается загрузить, он будет искать package.json в папке этого файла, затем в родительской папке этого файла и так далее, пока не достигнет корня тома. Это похоже на как Babel ищет файлы .babelrc. Этот новый подход позволяет Node.js использовать package.json для метаданных и конфигурации на уровне пакета, подобно тому, как он уже используется Babel и другими инструментами.

- флаг типа ввода

Используйте --input-type = module для запуска строкового ввода (через --eval, --print или STDIN ) как модуль ES. Флаг --input-type может иметь вид --input-type = module или --input-type = commonjs.

.cjs расширение

Так же, как расширение файла .mjs явно означает, что файл должен рассматриваться как модуль ES, новое расширение файла .cjs явно означает, что файл следует рассматривать как CommonJS . (CommonJS - это другая модульная система, поддерживаемая Node.js, с require и module.exports.) Расширение .cjs предоставляет способ сохранять файлы CommonJS в проекте, где оба .mjs и .js обрабатываются как модули ES.

Явные имена файлов

По умолчанию в новых --experimental-modules расширения файлов являются обязательными в операторах импорта: import './file.js', а не import './ файл '. Однако поведение автоматического разрешения расширений в стиле CommonJS ('./file') можно включить с помощью нового флага --es-module-спецификатор-разрешение = узел . (Его обратное значение по умолчанию - --es-module-спецификатор-разрешение = явное.) Имена пакетов по-прежнему являются просто именами пакетов, например импортировать файловую систему из "fs".

Мы предоставляем флаг --es-module-спецификатор-разрешение = узел, чтобы включить расширение в стиле CommonJS и разрешение индекса. Мы отключили его по умолчанию, чтобы собирать отзывы о том, как пользователи относятся к использованию полностью указанных путей, прежде чем мы снимаем отметку с реализации --experimental-modules. Нашу дискуссию по теме вы можете найти здесь.

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

module.createRequireFromPath

Глобальные объекты CommonJS (require, exports, module, __filename, __dirname ) не определены в модулях ES. Однако module.createRequireFromPath () можно использовать для создания функции CommonJS require, которая будет использоваться в контексте модуля ES.

импорт только для JavaScript

Предыдущий --experimental-modules позволял импортировать операторы JSON и собственных модулей. Это было удалено; для этого вы можете использовать module.createRequireFromPath ().

Отдельный флаг --experimental-json-modules включает экспериментальную поддержку импорта файлов JSON. Сейчас ведется работа по стандартизации этой функции с браузерами, и Node.js надеется привести нашу поддержку в соответствие со стандартом.

Также ведется работа по охвату WASM и других потенциальных типов модулей в будущем. Node.js со временем добавит их поддержку в соответствии со спецификацией.

Код модуля ES в пакетах

Эта работа находится в стадии разработки и может быть изменена. Вы можете создать пакет с исходными кодами модуля ES, используя поле package.json «main», чтобы указать на модуль ES. точка входа в пакет. Node.js будет знать, что нужно загрузить его как модуль ES, если файл заканчивается на .mjs или если package.json также содержит «type»: «module ”.

В настоящее время невозможно создать пакет, который можно использовать одновременно с помощью require (‘pkg’) и import ‘pkg’. В настоящее время предпринимаются усилия по решению этой проблемы, которые могут потребовать внесения изменений в вышеизложенное. В частности, Node.js может выбрать поле, отличное от «main», для определения точки входа модуля ES пакета. Хотя мы знаем, что сообщество приняло поле «module», маловероятно, что Node.js примет это поле, поскольку многие пакеты, опубликованные с использованием «module», включают JavaScript-модуль ES, который может не оценивать в Node.js (потому что в именах файлов не указаны расширения, или код включает операторы require и т. д.). Не публикуйте пакеты модулей ES, предназначенные для использования Node.js, пока проблема не будет решена.

В процессе

Все вышеперечисленное входит в состав --experimental-modules в Node.js 12. На нашей дорожной карте потенциальных улучшений до --experimental-modules Надеемся, что флаг будет снят в октябре 2019 года, когда Node.js 12 достигнет статуса LTS:

  • Особенности погрузчиков. Загрузчики дорабатываются для поддержки изоляции процессов, нескольких загрузчиков и поддержки нескольких областей с обработчиками нижнего уровня. API --loader все равно значительно изменится, прежде чем это будет снято.
  • Двойные пакеты модулей CommonJS / ES. Мы хотим предоставить авторам пакетов стандартный способ публикации пакета, который может потребоваться как в CommonJS, так и импортирован в модуль ES.
  • Проще потребовать. Использование Module.createRequireFromPath () требует большого количества шаблонов. Мы надеемся предоставить более простой способ использования require в коде модуля ES.
  • Карты путей к пакетам. Мы хотели бы поддерживать пути к файлам в пакетах. Это позволит таким вещам, как import sdk from 'some-service / sdk', иметь сопоставление 'some-service / sdk' с чем-то вроде ./src/sdk /public-api.mjs.
  • Автоматическое определение типа модуля точки входа. Это обеспечит способ запуска кода JavaScript в виде модулей CommonJS или ES на основе статического анализа.

Вот и все! Мы надеемся, что вам понравятся эти новые --experimental-modules, и ждем ваших отзывов. Работа команды модулей опубликована на https://github.com/nodejs/modules.