所以,我今天花了相当多的时间尝试放置完全使用 ESM(模块)的 NodeJS 应用程序,并且我已通过 cPanel 将其部署在使用 Node v. 14.20.1 的服务器上。我不断收到错误:
App 1153856 output: internal/modules/cjs/loader.js:948
App 1153856 output: throw new ERR_REQUIRE_ESM(filename);
App 1153856 output: ^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /<serverlocation>/app.js
App 1153856 output: at new NodeError (internal/errors.js:322:7)
App 1153856 output: at Module.load (internal/modules/cjs/loader.js:948:11)
App 1153856 output: at Function.Module._load (internal/modules/cjs/loader.js:790:12)
App 1153856 output: at Module.require (internal/modules/cjs/loader.js:974:19)
App 1153856 output: at Module.require (/opt/cpanel/ea-ruby27/root/usr/share/passenger/helper-scripts/node-loader.js:80:25)
所有文件都作为模块编写,我在任何地方都没有“require()”。
自从 Node 从 v14 开始完全支持 JS 模块,我大胆猜测我正在使用的托管服务器(及其 NodeJS 的 Passenger)正在使用一个在调用我的应用程序时使用“require()”的加载器.js 文件。 我尝试了多种解决方案,我什至将我的 app.js 文件切换为 CommonJS 类型,但随后它要求我将所有其他文件也切换为 CJS,这太麻烦了。
有人设法找到解决这个问题的方法吗?
对于任何试图解决此问题的人,这就是我解决它的方法:
1- 创建加载器脚本: 不一定与应用程序的主 app.js 文件位于同一文件夹中,但这是我创建它的位置。称其为 loader.cjs 之类的名称。如果你的 package.json 中有 "type": "module" ,那么扩展名为 .cjs 就很重要。 正如您可能已经猜到的,这将是您应用程序的新主目录。由于乘客的加载程序有 ES 模块的问题,只需让它加载一个 commonjs 文件即可。
2- 动态导入app.js: 您知道您仍然可以在commonjs 文件中加载ES 模块吗?你只需要一点额外的努力就能做到这一点。 显然,ES 模块是异步加载的,这对于同步的 commonjs 文件来说效果不佳。这就是你首先遇到这个问题的原因,对吧? 因此,解决方案是:动态导入。就像异步函数一样,将 ES 模块的导入视为承诺。我不太喜欢使用 .then(),所以我选择了 wait:
async function loadApp() {
await import("/path/to/app.js");
}
loadApp();
3-重命名你的app.js的扩展名:我不完全知道为什么这是必要的,但我收到了“无法找到/path/to/app.mjs”的错误,所以我改变了它至此。然后就成功了。您可以将上一点路径中的文件名保留为“app.js”,导入仍然会正确查找“app.mjs”;
可能有更有效的方法来做到这一点,但这就是我的两颗大脑所能想出的。希望它也能帮助其他人。
我按照上面的步骤操作,唯一的区别是在我的 loader.cjs 文件中我使用了:
async function loadApp() {
await import('./server.js')
}
loadApp()
server.js 文件位于根目录中。与 loader.cjs 相同的位置