如何欺骗Node.js加载.js文件作为ES6模块?

时间:2018-06-13 20:59:41

标签: javascript node.js ecmascript-6

Node.JS 10增加了对加载ES6模块的实验性支持,这些模块已经在浏览器中运行。这意味着我们最终可以为Node.JS和浏览器使用完全相同的文件而无需任何转换或polyfill。

除了我们不能。 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忽略扩展的一些技巧吗?

6 个答案:

答案 0 :(得分:1)

Node.js要求所有ES模块都应该具有.mjs扩展名。由于Node.js对ES模块的支持是实验性的,因此可能会发生变化。 A proposal和开放pull request预计会通过package.json esm标记和--mode选项来解决此问题。

目前可以通过挂钩到默认模块解析器并更改某些模块的模块类型的自定义ES module loader来解决这个问题:

定制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模块的评估方式存在根本差异,因此更改应限于需要它们的模块。

答案 1 :(得分:1)

我通过出色的esm软件包解决了这个问题。您可以在整个范围内启用动态(智能)esm模块加载程序包,或每次运行时都带有如下标记:

node -r esm your/es6/module.js

它还具有将每个文件或仅以'.mjs'结尾的文件都视为es6模块的选项。还有其他软件包,但是这个软件包确实有用。

答案 2 :(得分:1)

您现在可以分两个步骤将.js文件导入节点 v12.x

  • 在您的package.json文件中添加以下行:
// package.json
{
  "type": "module"
}
  • 在脚本前 前添加--experimental-modules标志
node --experimental-modules index.js

参考:https://nodejs.org/api/esm.html

答案 3 :(得分:0)

你可以这样做:

创建文件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

答案 4 :(得分:0)

使用与Node.js一起使用的ES6导入和导出模块

扩展名为.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

答案 5 :(得分:0)

这是一个满足您需求的模块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')

Reference & tests on Github