Мы уже упоминали о нескольких важных различиях между ESM и CommonJS, таких как необходимость явно указывать расширения файлов при импорте с помощью ESM, в то время как расширения файлов являются совершенно необязательными для функции CommonJS require.
Давайте завершим эту статью, обсудив некоторые другие важные различия между ESM и CommonJS и то, как две модульные системы могут работать вместе, когда это необходимо.
ECMAScript РАБОТАЕТ В СТРОГОМ РЕЖИМЕ
Модули ES выполняются неявно в строгом режиме. Это означает, что нам не нужно явно добавлять операторы use strict в начале каждого файла. Строгий режим нельзя отключить; поэтому мы не можем использовать необъявленные переменные или оператор with или иметь другие функции, доступные только в нестрогом режиме, но это, безусловно, хорошо, поскольку строгий режим является более безопасным режимом выполнения.
НЕДОСТАЮЩИЕ ССЫЛКИ В ECMAScript
В ESM некоторые важные ссылки CommonJS не определены. К ним относятся require , exports , module.exports , __filename и __dirname . Если мы попытаемся использовать любой из них в модуле ES, поскольку он также работает в строгом режиме, мы получим ReferenceError :
Мы уже подробно обсуждали значение экспорта и модуля в CommonJS; __filename и __dirname представляют абсолютный путь к текущему файлу модуля и абсолютный путь к его родительской папке. Эти специальные переменные могут быть очень полезны, когда нам нужно построить путь относительно текущего файла.
В ESM можно получить ссылку на URL текущего файла с помощью специального объекта import.meta . В частности, import.meta.url — это ссылка на файл текущего модуля в формате, подобном file:///path/to/current_module.js. Это значение можно использовать для восстановления __filename и __dirname в виде абсолютных путей:
import { fileURLToPath } from 'url' import { dirname } from 'path' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename)
Также можно воссоздать функцию require() следующим образом:
import { createRequire } from 'module' const require = createRequire(import.meta.url)
Теперь мы можем использовать require() для импорта функций из модулей CommonJS в контексте модулей ES.
Еще одним интересным отличием является поведение ключевого слова this.
В глобальной области модуля ES это не определено, а в CommonJS это является ссылкой на экспорты:
// this.js - ESM console.log(this) // undefined // this.cjs – CommonJS console.log(this === exports) // true
ВЗАИМОДЕЙСТВИЕ
В предыдущем разделе мы обсуждали, как импортировать модули CommonJS в ESM с помощью функции module.createRequire. Также можно импортировать модули CommonJS из ESM, используя стандартный синтаксис импорта. Однако это ограничено только экспортом по умолчанию:
import packageMain from 'commonjs-package' // Works import { method } from 'commonjs-package' // Errors
К сожалению, невозможно импортировать модули ES из модулей CommonJS.
Кроме того, ESM не может импортировать файлы JSON напрямую в виде модулей, что довольно часто используется с CommonJS. Следующий оператор import завершится ошибкой:
import data from './data.json'
Это приведет к ошибке TypeError ( Неизвестное расширение файла: .json ).
Чтобы преодолеть это ограничение, мы можем снова использовать утилиту module.createRequire:
import { createRequire } from 'module' const require = createRequire(import.meta.url) const data = require('./data.json') console.log(data)
В настоящее время ведется работа по встроенной поддержке модулей JSON даже в ESM, поэтому в ближайшем будущем нам может не понадобиться полагаться на createRequire() для этой функциональности.