Подробный обзор модулей 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.