Как обмануть Node.js для загрузки файлов.js в качестве модулей ES6?

В Node.JS 10 добавлена ​​экспериментальная поддержка загрузки модулей ES6, которые уже работают в браузерах. Это означало бы, что мы могли бы наконец использовать одни и те же файлы для Node.JS и браузеров без какой-либо транспиляции или полифилов.

За исключением того, что мы не можем. Node.js требует .mjs расширение для файлов, которые будут загружены в виде модулей. Я попытался обмануть узел, используя символическую ссылку, но узел обошел его:

D:\web\lines>node --experimental-modules ES6test.mjs
(node:7464) ExperimentalWarning: The ESM module loader is experimental.
D:\web\lines\ES6test.js:6
import myLibrary from "./MyFile.mjs";
       ^^^^^^^^^^^^^^^

Я не могу придумать никакого другого обходного пути, чтобы сделать эту работу - которая действительно делает поддержку всего модуля ES6 бесполезной.

Кто-нибудь еще может придумать, как заставить Node.js игнорировать расширение?

2 ответа

Теперь вы можете импортировать .jsфайл в узле v12.x, в 2 шага:

  • Добавьте следующую строку в свой package.json файл:
// package.json
{
  "type": "module"
}
  • добавлять --experimental-modulesфлаг перед скриптом:
node --experimental-modules index.js

Ссылка: https://nodejs.org/api/esm.html

Node.js требует, чтобы все модули ES имели расширение.mjs. Поскольку поддержка ES-модулей в Node.js является экспериментальной, это может измениться. Ожидается, что предложение и открытый запрос извлечения решат эту проблему с помощью package.json esm флаг и --mode вариант.

В настоящее время это может быть решено с помощью специального загрузчика модулей ES, который подключается к определителю модулей по умолчанию и изменяет тип модуля для некоторых модулей:

таможенно-loader.mjs

import path from 'path';

const ESM_WITH_JS_EXT = './MyFile.js'; // relative to loader path
const ESM_WITH_JS_EXT_URL = new URL(path.dirname(import.meta.url) + `/${ESM_WITH_JS_EXT}`).href;

export function resolve(specifier, parentModuleURL, defaultResolver) {
    const resolvedModule = defaultResolver(specifier, parentModuleURL);

    if (resolvedModule.url === ESM_WITH_JS_EXT_URL)
        resolvedModule.format = 'esm';

    return resolvedModule;
}

Используется как:

node --experimental-modules --loader ./custom-loader.mjs ./index.mjs

Поскольку существуют принципиальные различия в том, как оцениваются модули ES и CommonJS, изменения должны быть ограничены модулями, которые в них нуждаются.

Я решил именно эту проблему с помощью невероятного пакета ESM. Вы можете включить динамический (умный) модуль загрузки модуля esm для всего пакета или для каждого запуска с таким флагом:

node -r esm your/es6/module.js

Он также имеет опции для обработки каждого файла как модуля es6 или только тех, которые заканчиваются на ".mjs". Есть и другие пакеты, но этот просто сработал.

Импорт и экспорт модулей с использованием ES6, которые работают с Node.js

Называть файлы с .mjs расширение вместо .js

Создавать файлы

touch main.mjs lib.mjs

main.js

import { add } from './lib.mjs';
console.log(add(40, 2));

lib.mjs

export let add = (x,y) => {
  return x + y
}

Пробег

node --experimental-modules main.js

Вот модуль, который делает то, что вам нужно esmjs.mjs

import { readFileSync } from 'fs'
import { fileURLToPath, pathToFileURL } from 'url'
import { dirname, join } from 'path'

export const jsmodule = (test_url_or_path, module_path) => {

    const __filename = test_url_or_path.toLowerCase().startsWith('file:')
        ? fileURLToPath(test_url_or_path)
        : test_url_or_path

    const __dirname = dirname(__filename)

    const abs_path = join(__dirname, module_path)
    const file_url = pathToFileURL(abs_path)

    const file_buf = readFileSync(file_url)
    const b64 = file_buf.toString('base64')

    const moduleData = "data:text/javascript;base64," + b64

    return import(moduleData)
}

Использование из .mjs модуль:

const { hey } = await jsmodule(import.meta.url, '../../test-data/mjs.js')

Использование, от .js файл:

const { hey } = await jsmodule(__filename, '../../test-data/mjs.js')

Справочник и тесты на Github

Вы можете сделать это следующим образом:

Создайте файл module2.mjs (имя зависит от вас)

'use strict';

export function foo() {
    return 'foo';
}

Создайте файл index.mjs:

'use strict';

import { foo } from './module2.mjs';

console.log(foo());

Используя узел 8.11.1 (или 10), вы можете запустить его как (команда и вывод предоставляются):

node --experimental-modules index.mjs
(node:60428) ExperimentalWarning: The ESM module loader is experimental.
foo
Другие вопросы по тегам