Подробный обзор модулей ES (ESM)
npm — это менеджер пакетов для платформы JavaScript node.js. Он устанавливает модули так, чтобы узел мог их найти, и разумно управляет конфликтами зависимостей.
npm настраивается для поддержки различных вариантов использования для публикации, обнаружения, установки и разработки узловых программ. Он имеет список мощных команд.
npm 8 был выпущен 7 октября 2021 года. В этой статье мы рассмотрим npm 8 и предскажем, каким может быть npm 9.
Что нового в npm 8?
В npm 8 нет ничего нового. Цель этого выпуска — отказаться от поддержки старых версий узлов и удалить поддержку require('npm')
. Других критических изменений нет. В частности, это изменения:
- Прекратить поддержку узлов 10 и 11.
- Поднять потолок поддержки в узлах 12 и 14 до LTS (
^12.13.0
/^14.15.0
). - Прекратить поддержку
require('npm')
. - Обновите некоторые зависимости из-за отказа от поддержки node10 и node 11.
Это просто и понятно.
Если вы хотите перейти на npm 8, убедитесь, что ваш node.js обновлен до версии >=12.0.0
. nvm
— это простой способ управления версиями для node и npm.
Что может быть нового в npm 9?
Запрос комментариев (RFC) — это официальный документ, подготовленный Инженерной группой Интернета (IETF), в котором описаны спецификации для конкретной технологии. npm 8 — это ратифицированный RFC, в настоящее время формальный стандарт.
RRFC npm 8 упомянул предложение повысить поддерживаемые версии до ^12.20.0 || ^14.13.1 || >=16.0.0
, что будет означать переход к версиям node.js, поддерживающим модули в стиле ESM. Поскольку он не создавался в npm 8, возможно, это функция в npm 9.
CJS против ESM
Мы обсудили форматы модулей JavaScript, такие как CJS, AMD, UMD, ESM, System и IIFE.
CommonJS (CJS) — это стандарт, используемый node.js для инкапсуляции JavaScript в модулях. CJS использует функцию require()
и module.exports
.
require()
— это функция, которую можно использовать для импорта символов в текущую область видимости из другого модуля. Операторыrequire
можно использовать в любом месте кода, а соответствующие модули загружаются и обрабатываются синхронно.module.exports
— это объект, который возвращает текущий модуль, когда он требуется в другом модуле.
Модули ES (ESM) становятся официальным стандартом, используемым в JavaScript с ES2015. Он широко используется в разработке клиентов JavaScript. Он также принят TypeScript, который представляет собой надмножество с дополнительными типами. ESM использует операторы import
и export
для работы с модулями.
- Директива static
import
может использоваться для включения модулей в текущую область видимости. Динамическийimport()
доступен, поскольку операторы ES2020 .import
можно использовать в любом месте кода. Так какimports
загружаются асинхронно, рекомендуется размещать их вверху файлов. - Директива
export
, с другой стороны, может использоваться для явной публикации элементов.
CJS используется по умолчанию для узла
Как мы уже упоминали, CJS используется по умолчанию для node. Следуя шагам, описанным в готовом к работе приложении React, мы используем Создание приложения React в качестве примера, чтобы изучить, как работает сервер узла.
npx create-react-app react-esm cd react-esm
Выполните команду npm run build
, и созданный каталог build
будет содержать код для развертывания.
Express — это минимальная и гибкая платформа веб-приложений Node.js для веб-приложений и мобильных приложений. Express server — популярный выбор для развертывания производственной сборки.
Поскольку Express является частью приложения Create React, его не нужно устанавливать повторно.
Настройте файл конфигурации для сервера Express в server/index.js
:
Приведенный выше код, очевидно, имеет формат CJS с операторами require
(строка 1 и строка 4).
Строка 2 создает сервер Express.
Строки 5–8 обслуживают производственные веб-страницы.
Строки 10–12 запускают сервер Express на порту 8080
.
Запустите node server
, и пользовательский интерфейс будет доступен в http://localhost:8080
.
Установите узел для запуска ESM
Теперь мы изменим код, чтобы использовать import
вместо require()
.
Запускаем node server
, и видим следующую ошибку:
Предупреждение в строке 10 предлагает два решения:
- Установите
"type": "module"
вpackage.json
. - Измените
server/index.js
наserver/index.mjs
и запуститеnode server/index.mjs
.
Оба решения работают. Вот модифицированный package.json
(строка 5):
Файлы без расширений рассматриваются как модули CJS, если нет "type"
или в родительском package.json
установлен тип "commonjs"
. Они рассматриваются как модули ES, если "type"
установлено на "module"
.
Кроме того, файлы, заканчивающиеся на .cjs
, рассматриваются как модули CJS, а файлы, заканчивающиеся на .mjs
, рассматриваются как модули ES.
Мы устанавливаем "type"
в "module"
, теперь нода рассматривает файлы как модули ES. Запустите node server
еще раз:
Он больше не жалуется на import
. Но в чем проблема __dirname
?
__dirname
— переменная CJS, которая недоступна в модулях ES. Его можно воспроизвести через import.meta.url
.
Объект import.meta
предоставляет контекстно-зависимые метаданные модулю JavaScript. Он содержит информацию о модуле, например URL-адрес модуля.
Измените server/index.js
следующим образом:
Запустите node server
, и модуль ES работает отлично.
В качестве альтернативы у нас может быть префикс node:
, и в этом случае он обходит требуемый кеш. Например, "node:path"
(строка 4) и "node:url"
(строка 5) всегда будут возвращать встроенные модули "path"
и "url"
.
Мы видели некоторые различия между CJS и ESM. Ниже приведен список того, как преобразовать файлы CJS в модули ES:
- Нет
require
,exports
илиmodule.exports
— вместо них используйтеimport
илиexport
. - Нет
__filename
или__dirname
— вместо этого используйтеimport.meta.url
.
- Нет загрузки модуля JSON — вместо этого используйте
import.meta.url
сfs
.
- Нет загрузки собственного модуля — вместо этого используйте
module.createRequire()
илиprocess.dlopen
.
- Нет
require.resolve
— вместо этого используйтеnew URL('./local', import.meta.url)
. - Нет
NODE_PATH
— вместо этого используйте символические ссылки. - Нет
require.extensions
— Не использовать. - Нет
require.cache
— Не использовать.
Заключение
npm 8 прекратил поддержку узлов 10 и 11.
Что вы думаете о нпм 9? Должен ли он отказаться от поддержки версий узлов, которые не поддерживают модули ES?
После борьбы с различным синтаксисом для клиентов и серверов JavaScript, разве не приятно видеть, что ESM получает потоки, которые можно использовать как для клиентов, так и для серверов?
Пришло время использовать модули в стиле ESM в узловых приложениях.
Спасибо за прочтение. Я надеюсь, что это было полезно. Если вам интересно, ознакомьтесь с другими моими статьями на Medium.