无法启动使用ES模块的Node.js应用程序


我有一个简单的Node.js16.x应用程序。它使用ES模块,所以我在package.json中有"type": "module"。每当我使用npm脚本时,一切都很好。

现在我正在尝试使用Docker部署它,我不再需要npm脚本,所以我直接使用node二进制文件启动应用程序,就像我在package.json:node --require dotenv/config main.js中声明它一样。。。但这不起作用,它失败了,在ES模块周围出现了一条典型的错误消息,比如:

(node:9) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/opt/application/main.js:1
import { app } from "./application.js";
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47

我还按照本指南尝试了围绕该命令的设置组合:node --input-type=module --experimental-modules --require dotenv/config main.js,但仍然收到了相同的错误消息。

我想我在这里遗漏了一些琐碎的东西,所以我的问题是:我如何在不使用package.json(因为我现在已经没有它了(或仅使用node二进制文件将.js文件重命名为.mjs的情况下启动此应用程序?


这就是应用程序在文件系统中的样子(如果有什么不同的话(:

/opt/application # ls -ltr 
total 72
-rw-r--r--    1 root     root          2158 Oct 10 13:47 application.js
drwxr-xr-x    2 root     root          4096 Jan 27 14:57 support
-rw-r--r--    1 root     root           318 Jan 27 14:57 main.js
drwxr-xr-x    2 root     root          4096 Jan 27 14:57 handler
drwxr-xr-x    2 root     root          4096 Jan 27 14:57 config
-rw-r--r--    1 root     root          1448 Jan 27 14:58 knexfile.js
drwxr-xr-x    2 root     root          4096 Jan 27 16:57 service
drwxr-xr-x    2 root     root          4096 Jan 27 16:57 model
-rw-r--r--    1 root     root         28672 Jan 27 16:57 production.sqlite3
drwxr-xr-x  228 root     root         12288 Jan 27 16:57 node_modules
/opt/application # cat main.js 
import { app } from "./application.js";
import { logger } from "./config/winston.js";
import { SERVER_PORT } from "./support/constants.js";
const port = process.env.PORT || SERVER_PORT;
app.listen(port, () => {
logger.debug(`Server running at http://localhost:${port}`);
logger.info("Press CTRL-C to stop");
});

这是package.json文件的(摘录(:

{
"name": "node-express",
"private": true,
"type": "module",
"scripts": {
"develop": "nodemon --require dotenv/config src/server.js",
"start": "node --require dotenv/config src/server.js",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
},
"dependencies": {
"compression": "1.7.4",
"dotenv": "10.0.0",
"errorhandler": "1.5.1",
"express": "4.17.1",
"helmet": "4.6.0",
"http-status-codes": "2.1.4",
"lusca": "1.7.0",
"knex": "0.95.11",
"morgan": "1.10.0",
"objection": "2.2.16",
"sqlite3": "5.0.2",
"uuid": "8.3.2",
"winston": "3.3.3"
},
"devDependencies": {
"@jest/globals": "27.2.1",
"cross-env": "7.0.3",
"eslint-config-prettier": "8.3.0",
"eslint-config-recommended": "4.1.0",
"eslint-plugin-jest": "24.4.2",
"eslint-plugin-prettier": "4.0.0",
"eslint": "7.32.0",
"jest": "27.2.1",
"npm-run-all": "4.1.5",
"nodemon": "2.0.12",
"prettier": "2.4.1",
"supertest": "6.1.6"
},
"engines": {
"node": "16.x"
},
"jest": {
"collectCoverage": true,
"clearMocks": true,
"setupFiles": [
"dotenv/config"
],
"verbose": true
},
"nodemonConfig": {
"ignore": [
"*.test.js"
],
"watch": [
"src/*"
]
}
}

不幸的是,您想要做的是不可能的。来自节点文档:

Node.js将以下作为ES模块传递给节点初始输入,或者被ES中的导入语句引用时模块代码:

  • .mjs结尾的文件。

  • 当最近的父级package.json文件包含值为"module"的顶级"type"字段时,以.js结尾的文件。

  • 作为参数传入--eval的字符串,或通过STDIN管道传输到node的字符串,带有标志--input-type=module

如果可能的话,您应该只复制Dockerfile中的package.json——这正是Node所期望的。

否则,如果你的Docker镜像中绝对不能有package.json,那么node --input-type module --require dotenv/config < main.js就可以了。

最新更新