我的目标是获得一个我可以在任何地方执行的 cli。
似乎更好的方法是全局安装。
但是当我尝试时,它会引发一个错误,就像缺少必需的模块一样。
npm install -g <missing_module>
后也无法解决这个问题
我正在使用具有多个节点版本的 nvm,所以我认为这可能是根本原因。 但是当我检查当前使用的节点版本的 node_modules 时,我发现缺少模块。
我不明白。
我把重现的步骤放在这里,用一个小例子 test2 项目。 请注意,我的问题来自另一个大项目,我在 dotenv-safe/config 上也遇到了问题。
如果我解决这个给定的例子,我想我将能够解决其他缺失的模块。
$ mkdir -p test2
$ cd test2
$ npm init -y
$ echo '[{"key": "1"}]' > jsonFile.json
$ touch index.js
$ chmod +x index.js
在 package.json 中添加:
"type": "module",
"bin": {
"test2-cli": "./index.js"
},
$ cat index.js
#!/usr/bin/env node
import jsonContent from './jsonFile.json' assert { type: "json"}
console.log(jsonContent)
$ ./index.js
[ { key: '1' } ]
(node:5362) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
按照 João Pimentel 的建议,我添加了
--experimental-modules
标签。
而且我不想要警告,所以我添加了--require=suppress-experimental-warnings
选项。
所以我换成
index.js
#!/usr/bin/env node
by
#!/usr/bin/env -S node --experimental-modules --require=suppress-experimental-warnings
$ ./index.js
node:internal/modules/cjs/loader:1042
throw err;
^
Error: Cannot find module 'suppress-experimental-warnings'
Require stack:
- internal/preload
at Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
at Module._load (node:internal/modules/cjs/loader:885:27)
at Module.require (node:internal/modules/cjs/loader:1105:19)
at Module._preloadModules (node:internal/modules/cjs/loader:1395:12)
at loadPreloadModules (node:internal/process/pre_execution:621:5)
at setupUserModules (node:internal/process/pre_execution:125:3)
at prepareExecution (node:internal/process/pre_execution:116:5)
at prepareMainThreadExecution (node:internal/process/pre_execution:36:3)
at node:internal/main/run_main_module:10:1 {
code: 'MODULE_NOT_FOUND',
requireStack: [ 'internal/preload' ]
}
Node.js v18.13.0
$ npm install suppress-experimental-warnings
added 1 package in 536ms
1 package is looking for funding
run `npm fund` for details
$ ./index.js
[ { key: '1' } ]
好的,现在我想在终端的任何地方访问这个 cli。
$ npm install -g .
added 2 packages in 1s
1 package is looking for funding
run `npm fund` for details
$ cd ../
$ test2-cli
node:internal/modules/cjs/loader:1042
throw err;
^
Error: Cannot find module 'suppress-experimental-warnings'
Require stack:
- internal/preload
at Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
at Module._load (node:internal/modules/cjs/loader:885:27)
at Module.require (node:internal/modules/cjs/loader:1105:19)
at Module._preloadModules (node:internal/modules/cjs/loader:1395:12)
at loadPreloadModules (node:internal/process/pre_execution:621:5)
at setupUserModules (node:internal/process/pre_execution:125:3)
at prepareExecution (node:internal/process/pre_execution:116:5)
at prepareMainThreadExecution (node:internal/process/pre_execution:36:3)
at node:internal/main/run_main_module:10:1 {
code: 'MODULE_NOT_FOUND',
requireStack: [ 'internal/preload' ]
}
Node.js v18.13.0
$ npm install -g suppress-experimental-warnings
added 1 package in 534ms
1 package is looking for funding
run `npm fund` for details
$ test2-cli
node:internal/modules/cjs/loader:1042
throw err;
^
Error: Cannot find module 'suppress-experimental-warnings'
Require stack:
- internal/preload
at Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
at Module._load (node:internal/modules/cjs/loader:885:27)
at Module.require (node:internal/modules/cjs/loader:1105:19)
at Module._preloadModules (node:internal/modules/cjs/loader:1395:12)
at loadPreloadModules (node:internal/process/pre_execution:621:5)
at setupUserModules (node:internal/process/pre_execution:125:3)
at prepareExecution (node:internal/process/pre_execution:116:5)
at prepareMainThreadExecution (node:internal/process/pre_execution:36:3)
at node:internal/main/run_main_module:10:1 {
code: 'MODULE_NOT_FOUND',
requireStack: [ 'internal/preload' ]
}
Node.js v18.13.0
$ nvm ls
v6.14.4
v14.15.5
v16.10.0
v16.17.0
-> v18.13.0
v19.5.0
default -> lts/* (-> v18.13.0)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v19.5.0) (default)
stable -> 19.5 (-> v19.5.0) (default)
lts/* -> lts/hydrogen (-> v18.13.0)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.2 (-> N/A)
lts/gallium -> v16.19.0 (-> N/A)
lts/hydrogen -> v18.13.0
$ npm prefix -g
/home/bjam/.nvm/versions/node/v18.13.0
$ ls -la /home/bjam/.nvm/versions/node/v18.13.0/lib/node_modules/ | grep suppress-
drwxr-xr-x 3 bjam bjam 4096 Mar 17 11:00 suppress-experimental-warnings
使用
require
代替,因为不完全支持import
,除非你使用--experimental-modules
标签,例如:node --experimental-modules index.js
与
require
:
#!/usr/bin/env node
const fs = require('fs')
const jsonContent = JSON.parse(fs.readFileSync('./jsonFile.json'))
console.log(jsonContent)
我找到了一种解决方法,通过将
readFileSync
替换为实验性 json 导入,结合 URL
和 import.meta.url
来解析项目的相对路径。
#!/usr/bin/env -S node
import { readFileSync } from 'fs'
const filePath = new URL('jsonFile.json', import.meta.url)
const jsonContent = JSON.parse(readFileSync(filePath, 'utf-8'))
console.log(jsonContent)
对于
readFileSync
,必须考虑相对路径是相对于当前工作目录(调用脚本的位置)而不是相对于项目(存储package.json
的位置)。
当前工作目录的相对路径:
readFileSync('jsonFile.json', 'utf-8')
当前文件的相对路径:
new URL('jsonFile.json', import.meta.url)