Текущий статус поддержки ECMAScript-модулей (ESM) в Node.js:
- Экспериментальная поддержка ESM была добавлена в Node.js 8.5.0 12 сентября 2017 года.
- После этого Технический Руководящий Комитет Node.js сформировал команду, ответственную за модули (Modules Team), чтобы она помогла спроектировать недостающие части для грядущего (не экспериментального) релиза. Эта команда состоит из людей из различных отраслей веб-разработки (фронтенд, бекенд, JS-движки, и т.д.).
В октябре Modules Team опубликовала "План по реализации Новых Модулей". Этот пост объясняет, что в нем содержится.
Фазы
Процесс разделен на три фазы:
- Фаза 1: создать "минимальное" ядро – основной набор правил и возможностей, минимальных и бесспорных, насколько это возможно.
- Фаза 2 и далее: создание на основе ядра более сложной функциональности.
Минимальное ядро будет основой для последующей работы. Новый дизайн также заменит текущую экспериментальную реализацию, как только обзаведется аналогичными возможностями.
Фаза 1: минимальное ядро поддержки ESM в Node.js
Упрощение идентификаторов модулей
Одна из целей Modules Team это достижение "браузерной эквивалентности": Node.js должна быть близка по поведению к браузерам, насколько это возможно. Ядро достигает этого путем упрощения разбора идентификаторов модулей (URL-ов, указывающих на модули):
- Каждый идентификатор модуля должен заканчиваться именем файла с расширением. То есть
- Расширения не добавляются автоматически
- Импортирование директорий не поддерживается (ни через перенаправление на
dir/index.mjs
, ни чтение поляmain
вpackage.json
).
- ES modules могут импортировать встроенные Node.js-модули (
path
и подобные). Они являются единственным исключением из предыдущего правила. - По умолчанию поддерживаются только файлы с расширением
.mjs
(смотрите Фазу 2, если вам интересен статус других расширений). Таким образом, другие виды модулей не смогут быть импортированы черезimport
: модули CommonJS, JSON-файлы, нативные модули.
Принесение важных возможностей CommonJS в ES-модули
- URL текущего модуля (аналогично
__filename
из CommonJS): import.meta.url - Динамический импорт ES-модулей (доступен через
require()
в CommonJS):оператор import()
Совместимость
- ES-модули смогут импортировать CommonJS-модули через
createRequireFromPath()
. Это будет работать следующим образом (есть планы сделать сокращенный способ, например, функциюcreateRequireFromUrl()
):
import {createRequireFromPath as createRequire} from 'module';
import {fileURLToPath as fromPath} from 'url';
const require = createRequire(fromPath(import.meta.url));
const cjsModule = require('./cjs-module.js');
- CommonJS-модули смогут загружать ES-модули через
import()
.
Фаза 2 и дальнейшие планы
- Во второй фазе нас ждет:
- Поддержка "bare" индентификаторов, таких как
'lodash'
. Скорее всего, это включит в себя некоторый способ маппинга этих идентификаторов на реальные пути. - Поддержка других расширений файлов, помимо
.mjs
. Это включает в том числе и поддержку ES-модулей в.js
файлах.
- Поддержка "bare" индентификаторов, таких как
- Фаза 3, скорее всего, сосредоточится на загрузчиках модулей с точками расширения, в которых пользователи смогут подключить свою логику.
Когда я смогу пользоваться ES-модулями в Node.js?
- За флагом: доступно уже сейчас
- Внимание: поведение еще не соответствует описанному выше в фазе 1 (по состоянию на Node.js 11.5.0)
- Без флага и в соотвествии с фазой 1: Modules Team старается сделать это возможным как можно скорее. Надеемся, что модули выпустят из под флага в Node.js 14 (апрель 2020 года) и портируют в предыдущие версии, если это будет возможно.
Часто задаваемые вопросы
- Зачем нужно новое расширение файлов
.mjs
?
- Каждое решение по различению форматов ESM и CommonJS имеет свои преимущества и недостатки. Использование отдельного разрешения кажется неплохим вариантом (больше информации).
- Почему поведение Node.js должно быть похожим на браузерное?
- Потому что это делает возможным переиспользование кода. Например, чтобы создавать библиотеки, которые работают одновременно и в браузерах, и в Node.js
- Также это должно облегчить переключение между бекендом и фронтендом во время кодинга.
- К чему все эти ограничения в целях совместимости?
- Между ES и CommonJS-модулями есть довольно сильные отличия в структуре (статическая против динамической) и способе загрузки (асинхронная против синхронной). Ограничения помогают сохранить порядок вещей простым – учитывая, что в долгосрочной перспективе подавляющим большинством будут ES-модули.
- Почему это все тянется так долго?
- Здесь участвует много заинтересованных сторон и вовлечено много разных платформ (Node.js, npm, браузеры, JS-движки, TypeScript, TC39 и другие). Если мы действительно получим ES-модули, способные работать везде, наверное, это стоит ожидания, ИМХО.
Благодарность
Спасибо Майлсу Боринсу за его отзывы об этом посте.
Дополнительные источники для дальнейшего чтения
- "План по реализации Новых Модулей" от Node.js Foundation Modules Team
- Глава "Модули" из "Javascript для нетерпеливых программистов" (поясняет особенности скриптов, CommonJS и ES-модулей)
- Изначальное поведение экспериментальной версии ESM в Node.js описано в моем предыдущем посте.