Модули ECMAScript
Node.js содержит поддержку ES Модулей, основанную на Node.js EP для ES Модулей.
Не все функции EP завершены и будут добавлены по мере готовности поддержки VM и реализации. Сообщения об ошибках всё ещё дорабатываются.
Включение
Флаг --experimental-modules может быть использован для включения функций загрузки ESM-модулей.
После установки, файлы с расширением .mjs смогут загружаться как ES Модули.
node --experimental-modules my-app.mjs
Функции
Поддерживаемые
Только аргумент командной строки для основной точки входа в программу может быть точкой входа в граф ESM. Динамический импорт также может быть использован для создания точек входа в графы ESM во время выполнения.
import.meta
Свойство import.meta является Object, содержащим следующее свойство:
-
url<строка> Абсолютныйfile:URL модуля.
Неподдерживаемые
| Функция | Причина |
|---|---|
require('./foo.mjs') |
ES Модули имеют разные правила разрешения и временные интервалы, используйте динамический импорт |
Существенные различия между import и require
Отсутствует NODE_PATH
NODE_PATH не участвует в разрешении import спецификаторов. Пожалуйста, используйте символические ссылки, если это поведение необходимо.
Отсутствует require.extensions
require.extensions не используется import. Ожидается, что в будущем, обработчики загрузчиков смогут обеспечить этот рабочий процесс.
Отсутствует require.cache
require.cache не используется import. У него есть отдельный кэш.
Пути, основанные на URL
ESM разрешаются и кэшируются на основе семантики URL. Это означает, что файлы, содержащие специальные символы, такие как # и ?, должны быть закодированы.
Модули будут загружаться несколько раз, если спецификатор import используемый для их разрешения, имеет разный запрос или фрагмент.
import './foo?query=1'; // loads ./foo with query of "?query=1" import './foo?query=2'; // loads ./foo with query of "?query=2"
В данный момент загрузить могут только модули, использующие протокол file:.
Взаимодействие с существующими модулями
Все модули CommonJS, JSON и C++ могут быть использованы с import.
Загруженные таким образом модули будут загружены только один раз, даже если их строка запроса или фрагмент отличаются между import операторами.
При загрузке через import эти модули предоставят единый default экспорт, представляющий значение module.exports на момент завершения их оценки.
// foo.js
module.exports = { one: 1 };
// bar.mjs
import foo from './foo.js';
foo.one === 1; // true
Встроенные модули предоставят именованные экспорты своей публичной API, а также экспорт по умолчанию, который может быть использован, среди прочего, для модификации именованных экспортов. Именованные экспорты встроенных модулей обновляются при доступе, переопределении или удалении соответствующего свойства exports.
import EventEmitter from 'events'; const e = new EventEmitter();
import { readFile } from 'fs';
readFile('./foo.txt', (err, source) => {
if (err) {
console.error(err);
} else {
console.log(source);
}
});
import fs, { readFileSync } from 'fs';
fs.readFileSync = () => Buffer.from('Hello, ESM');
fs.readFileSync === readFileSync;
Обработчики загрузчиков
Для настройки стандартного разрешения модулей можно использовать опциональные обработчики загрузчиков, предоставленные через аргумент --loader ./loader-name.mjs для Node.js.
При использовании обработчиков, они применяются только к загрузке ES-модулей, а не к любым загруженным модулям CommonJS.
Обработчик разрешения
Обработчик разрешения возвращает разрешённый URL файла и формат модуля для заданного спецификатора модуля и родительского URL файла:
const baseURL = new URL('file://');
baseURL.pathname = `${process.cwd()}/`;
export async function resolve(specifier,
parentModuleURL = baseURL,
defaultResolver) {
return {
url: new URL(specifier, parentModuleURL).href,
format: 'esm'
};
}
parentModuleURL предоставляется как undefined при выполнении основной загрузки Node.js.
Функция стандартного разрешения Node.js для ES модулей предоставлена в качестве третьего аргумента резольверу для упрощения работы по обеспечению совместимости.
В дополнение к возвращаемому значению разрешённого URL файла, обработчик разрешения также возвращает свойство format, определяющее формат модуля, полученного в результате разрешения. Это может быть одно из следующих значений:
format |
Описание |
|---|---|
'esm' |
Загрузка стандартного JavaScript-модуля |
'cjs' |
Загрузка модуля CommonJS в стиле Node |
'builtin' |
Загрузка встроенного модуля CommonJS Node |
'json' |
Загрузка JSON-файла |
'addon' |
Загрузка C++ Плагина |
'dynamic' |
Использование обработчика динамической инициализации |
Например, фиктивный загрузчик, загружающий JavaScript, ограниченный правилами разрешения браузера, с поддержкой только расширения JS файлов и встроенных модулей Node.js, можно написать:
import path from 'path';
import process from 'process';
import Module from 'module';
const builtins = Module.builtinModules;
const JS_EXTENSIONS = new Set(['.js', '.mjs']);
const baseURL = new URL('file://');
baseURL.pathname = `${process.cwd()}/`;
export function resolve(specifier, parentModuleURL = baseURL, defaultResolve) {
if (builtins.includes(specifier)) {
return {
url: specifier,
format: 'builtin'
};
}
if (/^\.{0,2}[/]/.test(specifier) !== true && !specifier.startsWith('file:')) {
// For node_modules support:
// return defaultResolve(specifier, parentModuleURL);
throw new Error(
`imports must begin with '/', './', or '../'; '${specifier}' does not`);
}
const resolved = new URL(specifier, parentModuleURL);
const ext = path.extname(resolved.pathname);
if (!JS_EXTENSIONS.has(ext)) {
throw new Error(
`Cannot load file with non-JavaScript file extension ${ext}.`);
}
return {
url: resolved.href,
format: 'esm'
};
}
С этим загрузчиком, выполнение:
NODE_OPTIONS='--experimental-modules --loader ./custom-loader.mjs' node x.js
загрузит модуль x.js как ES-модуль с поддержкой относительного разрешения (с node_modules пропускается в данном примере).
Обработчик динамической инициализации
Для создания настраиваемого динамического модуля, который не соответствует одному из существующих format интерпретаций, может быть использован обработчик dynamicInstantiate. Этот обработчик вызывается только для модулей, которые возвращают значение format: 'dynamic' из обработчика resolve.
export async function dynamicInstantiate(url) {
return {
exports: ['customExportName'],
execute: (exports) => {
// get and set functions provided for pre-allocated export names
exports.customExportName.set('value');
}
};
}
С предоставленным списком экспортов модулей, функция execute будет вызвана в точный момент оценки модуля в порядке импорта для этого модуля в дереве импортов.
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v10.x/docs/api/esm.html