无法启动 Node.js 使用 ES 模块的应用程序
Unable to start Node.js application that uses ES module
我有一个简单的 Node.js 16.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
by following this guide,但我仍然收到相同的错误消息。
我想我在这里遗漏了一些微不足道的东西,所以我的问题是:如何在不使用 package.json
(因为此时我不再拥有它)或重命名 .js
文件到 .mjs
,仅使用 node
二进制文件?
这是应用程序在文件系统中的样子(如果它有任何不同):
/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 documentation:
Node.js will treat the following as ES modules when passed to node as
the initial input, or when referenced by import statements within ES
module code:
Files ending in .mjs
.
Files ending in .js
when the nearest parent package.json
file contains a top-level "type"
field with a value of "module"
.
Strings passed in as an argument to --eval
, or piped to node
via STDIN
, with the flag --input-type=module
.
如果可能,您应该只复制 Docker 文件中的 package.json
- 这正是 Node 所期望的。
否则,如果您绝对不能在 Docker 图像中使用 package.json
,那么 node --input-type module --require dotenv/config < main.js
应该可以解决问题。
我有一个简单的 Node.js 16.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
by following this guide,但我仍然收到相同的错误消息。
我想我在这里遗漏了一些微不足道的东西,所以我的问题是:如何在不使用 package.json
(因为此时我不再拥有它)或重命名 .js
文件到 .mjs
,仅使用 node
二进制文件?
这是应用程序在文件系统中的样子(如果它有任何不同):
/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 documentation:
Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:
Files ending in
.mjs
.Files ending in
.js
when the nearest parentpackage.json
file contains a top-level"type"
field with a value of"module"
.Strings passed in as an argument to
--eval
, or piped tonode
viaSTDIN
, with the flag--input-type=module
.
如果可能,您应该只复制 Docker 文件中的 package.json
- 这正是 Node 所期望的。
否则,如果您绝对不能在 Docker 图像中使用 package.json
,那么 node --input-type module --require dotenv/config < main.js
应该可以解决问题。