在实际问题之前(见文末),请让我通过一个例子展示导致该问题的步骤:
tests$ mkdir esm && cd esm
tests/esm$ nvm -v
0.37.2
tests/esm$ nvm use v15
Now using node v15.6.0 (npm v7.5.6)
tests/esm$ node -v
v15.6.0
tests/esm$ npm -v
7.5.6
tests/esm$ npm init
package name: (esm) test-esm
entry point: (index.js)
安装nodehun
tests/esm$ npm install nodehun
added 2 packages, and audited 3 packages in 11s
tests/esm$ npm ls
[email protected] tests/esm
└── [email protected]
index.js
import { suggest } from './checker.js'
suggest("misspeling");
checker.js
import Nodehun from 'nodehun'
import fs from 'fs';
const affix = fs.readFileSync('dictionaries/en_NZ.aff')
const dictionary = fs.readFileSync('dictionaries/en_NZ.dic')
const nodehun = new Nodehun(affix, dictionary)
export const suggest = (word) => hun_suggest(word);
async function hun_suggest(word) {
let suggestions = await nodehun.suggest(word);
console.log(suggestions);
}
要获取所需的Hunspell 词典文件(aff
ix 和dic
tionary):
tests/esm$ mkdir dictionaries && cd dictionaries
tests/esm/dictionaries$ curl https://www.softmaker.net/down/hunspell/softmaker-hunspell-english-nz-101.sox > en_NZ.sox
tests/esm/dictionaries$ unzip en_NZ.sox en_NZ.aff en_NZ.dic
根据nodejs
文档(确定模块系统)支持import
/ export
:
Node.js的将把以下作为ES模块传递到当
node
作为初始输入时,或者当通过引用import
ES模块代码内的语句:•文件中结束.js
时,最近的父package.json
文件包含一个顶层的“类型”与值字段"module"
.
我们在项目"type": "module"
的package.json
文件中添加字段。
package.json
{
...
"main": "index.js",
"type": "module",
...
}
第一次失败的运行
tests/esm$ node index.js
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".node" for tests/esm/node_modules/nodehun/build/Release/Nodehun.node
... omitted ...
at async link (node:internal/modules/esm/module_job:64:9) {
code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
挖掘一下上述错误的原因:
require
已编译的插件二进制文件的文件扩展名是
.node
(与.dll
或相对.so
)。编写 require() 函数以查找具有.node
文件扩展名的文件并将它们初始化为动态链接库。
"type": "module"
,require
它就不再受支持(如Interoperability with CommonJS 中所述):使用
require
加载的ES模块不支持,因为ES模块具有异步执行。相反,使用 import() 从 CommonJS 模块加载 ES 模块。
临时解决方案
经过一段时间搜索文档,我找到了一个临时解决方案:自定义 ESM 说明符解析算法:
当前的说明符解析不支持 CommonJS 加载器的所有默认行为。行为差异之一是文件扩展名的自动解析以及导入具有索引文件的目录的能力。该
--experimental-specifier-resolution=[mode]
标志可用于自定义扩展解析算法。要启用自动扩展解析并从包含索引文件的目录导入,请使用该node
模式。
tests/esm$ node --experimental-specifier-resolution=node index.js
(node:XXXXX) ExperimentalWarning: The Node.js specifier resolution in ESM is experimental.
(Use `node --trace-warnings ...` to show where the warning was created)
[
'misspelling',
'misspending',
'misspeaking',
'misspell',
'dispelling',
'misapplier',
'respelling'
]
有一些帖子达到了相同的分辨率(参考 1,参考 2)。但是,使用实验性标志似乎不是在生产中运行应用程序的正确方法。
失败的esm
包替代方案
从那时起,已经尝试了几次失败的尝试来避免使用--experimental-*
标志。进行了一些搜索,我发现了一些推荐使用该软件包的帖子(参考 1、参考 2)esm
。
但是,此时,当我尝试此操作时node -r esm index.js
,会出现一个新错误:
tests/esm$ npm install esm
added 1 package, and audited 4 packages in 709ms
tests/esm$ npm ls
[email protected] tests/esm
├── [email protected]
└── [email protected]
tests/esm$ node -r esm index.js
tests/esm/index.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: tests/esm/index.js
at new NodeError (node:internal/errors:329:5)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1125:13) {
code: 'ERR_REQUIRE_ESM'
}
以上可能是由于报告的问题(错误 [ERR_REQUIRE_ESM]:必须使用导入加载 ES 模块 / ES 模块的 require() 不受支持)。
const module = require('module');
module.Module._extensions['.js'] = function(module, filename) {
const content = fs.readFileSync(filename, 'utf8');
module._compile(content, filename);
};
import
/ export
(ES 模块)而不会引起import
插件问题?
--experimental-specifier-resolution=node
标志。esm
可以解决上述问题。使用esm
包有什么问题吗?
任何帮助解决它的提示将不胜感激。
注意:示例的最终状态可以从https://github.com/rellampec/test-esm.git克隆
经过一番胡说八道,试图找出这个问题的根本原因。
使用时node -r esm index.js
,该esm
软件包已经为您完成了所有工作(如其他答案中所述),因此(其他答案中未提及):
package.json
应由被更新删除"type:" "module"
(因为它创造了本土之间希望的交互node
ES模块的功能和esm
安装包)旁注:如果您尝试使用node
ES 模块,然后尝试切换到esm
包,则很容易错过这一点。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句