Spec-Zone.ru › Node.js 10 LTS

Модули ECMAScript

Устойчивость: 1 - Экспериментальная

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API