从concomjs导入ES 6模块
#javascript #typescript #node #ecmascript

几天前在Liferay,我们需要使用p-map包。只有一个问题:我们的应用程序仍然使用CommonJS格式,而P-MAP仅发布ES6 modules。即使我发现的一些最好的参考文献(例如this post)也明确表明,不可能从Commonjs导入ES6模块。

好消息是,这不再是真的!使用dynamic koude0,我们可以从commonjs加载ES6模块。让我们看一个例子。

在此project中,koude1文件试图使用require()导入ES6模块:

const pmap = require('p-map');

exports.importer = () => {
  console.log('Yes, I could import p-map:', pmap);
}

当然没有工作:

$ node index.js 
internal/modules/cjs/loader.js:1102
      throw new ERR\_REQUIRE\_ESM(filename, parentPath, packageJsonPath);
      ^

Error \[ERR\_REQUIRE\_ESM\]: Must use import to load ES Module: /home/adam/software/es6commonjs/node\_modules/p-map/index.js
require() of ES modules is not supported.
require() of /home/adam/software/es6commonjs/node\_modules/p-map/index.js from /home/adam/software/es6commonjs/importer.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/adam/software/es6commonjs/node\_modules/p-map/package.json.

    at new NodeError (internal/errors.js:322:7)
    at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1102:13)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module.\_load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/home/adam/software/es6commonjs/importer.js:1:14)
    at Module.\_compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32) {
  code: 'ERR\_REQUIRE\_ESM'
}

解决方案是将require()转换为动态import,这是一种语法,我们调用import命令,就好像它是一个异步函数一样。但是有一个细节:导入导入返回Promises。有很多方法可以解决这个问题。最简单的可能是使我们的功能异步,例如this version

exports.importer = async () => {
  const pmap = await import('p-map');
  console.log('Yes, I could import p-map:', pmap);
}

现在我们的小应用程序可行!

$ node index.js 
ok
Yes, I could import p-map: \[Module: null prototype\] {
  AbortError: \[class AbortError extends Error\],
  default: \[AsyncFunction: pMap\],
  pMapSkip: Symbol(skip)
}

可能需要其他一些调整。 (例如,我必须调整eslint设置。)重要的是这是可能的。这不是一个kludge:Node’s own documentation recommends this approach

因此,不要因为过时的信息而害怕:至少目前,您需要将整个应用程序重写为ES 6模块。对我们来说,这是一个宽慰!https://suspensao.blog.br/disbelief/importing-es-6-modules-from-commonjs/

(来自Wikimedia Commons的封面图像。)
Importing ES 6 Modules from CommonJS帖子首次发表在Suspension of Disbelief中。)