"Error: ENOENT: no such file or directory" after installing global npm package
"Error: ENOENT: no such file or directory" after installing global npm package
我刚刚将我的第一个 Node.js CLI 工具包 youtube-playlist-export
发布到 npm,但是当我试图通过将它安装到我的本地计算机来测试我的包时,它给出了“错误:ENOENT:没有这样的文件或目录”警告。
重现步骤
首先打开Terminal,当前直接工作的应该是home文件夹。
接下来,全局安装包:
$ npm install -g youtube-playlist-export
added 397 packages, and audited 398 packages in 18s
67 packages are looking for funding
run `npm fund` for details
10 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
最后,运行 ytpl-export
命令启动 运行CLI 应用程序。它将给出“错误:ENOENT:没有这样的文件或目录”警告。
$ ytpl-export
(node:4632) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open 'C:\Users\User\package.json'
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4632) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:4632) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
附加信息
这是 project repository 的简要结构:
.
├── source/
│ ├── cli.js
│ └── ...
├── tests/
└── package.json
在package.json
中,我将"bin"
字段定义为具有"ytpl-export"
属性的对象,其字段为"./source/cli.js"
。这会在终端中注册 ytpl-export
命令,这样它将 运行 我的 CLI 应用程序。
{
"name": "youtube-playlist-export",
"version": "1.0.2",
"engines": {
"node": ">=12"
},
"files": [
"source"
],
"bin": {
"ytpl-export": "./source/cli.js"
}
}
这里是源代码 source/cli.js
:
#!/usr/bin/env node
import c from "chalk";
import { program } from "commander";
import { readPackage } from "read-pkg";
import updateNotifier from "update-notifier";
import idActionHandler from "./commands/id.js";
import keyActionHandler from "./commands/key.js";
import configActionHandler from "./commands/config.js";
(async () => {
const pkg = await readPackage();
updateNotifier({ pkg }).notify();
program.name("ytpl-export").version(pkg.version);
program.addHelpText("before", "Exports video data from a YouTube playlist to JSON/CSV file.\n");
program
.command("id")
.description("Export video metadata of a playlist by its playlist ID.")
.argument(
"<playlistId>",
// prettier-ignore
`The value of the "list" parameter in the the playlist homepage URL (https://www.youtube.com/playlist?list=${c.greenBright("[playlistId]")})`
)
.option("-d, --default", "Skip all questions and use the default config")
.addHelpText(
"after",
`
Example:
$ ytpl-export id PLBCF2DAC6FFB574DE
`
)
.action(idActionHandler);
program.command("key").description("Manage your YouTube API key.").action(keyActionHandler);
program
.command("config")
.description("Edit configurations of this app.")
.option("-p, --path", "show the path of the config file")
.option("-r, --reset", "reset all configurations to default")
.action(configActionHandler);
program.parse(process.argv);
})();
问题原因
感谢Darth的评论,这个问题是由cli.js
中的const pkg = await readPackage();
行引起的:
#!/usr/bin/env node
import { readPackage } from "read-pkg";
/* ... */
(async () => {
const pkg = await readPackage(); // THIS LINE
/* ... */
})();
根据read-pkg
's documentation,如果我们不为readPackage()
提供cwd
选项,cwd
的默认值是process.cwd()
(当前工作目录)。由于我运行 ytpl-export
在主目录下,readPackage()
会尝试读取主目录下的package.json
,它不存在
解决方案
- 安装
get-installed-path
,returns模块安装路径的包到项目:
$ yarn add get-installed-path
- 编辑
cli.js
,使 readPackage()
将从安装路径读取 package.json
文件:
#!/usr/bin/env node
import { getInstalledPath } from "get-installed-path";
import { readPackage } from "read-pkg";
/* ... */
(async () => {
const installedPath = await getInstalledPath("youtube-playlist-export");
const pkg = await readPackage({ cwd: installedPath });
/* ... */
})();
我刚刚将我的第一个 Node.js CLI 工具包 youtube-playlist-export
发布到 npm,但是当我试图通过将它安装到我的本地计算机来测试我的包时,它给出了“错误:ENOENT:没有这样的文件或目录”警告。
重现步骤
首先打开Terminal,当前直接工作的应该是home文件夹。
接下来,全局安装包:
$ npm install -g youtube-playlist-export
added 397 packages, and audited 398 packages in 18s
67 packages are looking for funding
run `npm fund` for details
10 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
最后,运行 ytpl-export
命令启动 运行CLI 应用程序。它将给出“错误:ENOENT:没有这样的文件或目录”警告。
$ ytpl-export
(node:4632) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open 'C:\Users\User\package.json'
(Use `node --trace-warnings ...` to show where the warning was created)
(node:4632) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:4632) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
附加信息
这是 project repository 的简要结构:
.
├── source/
│ ├── cli.js
│ └── ...
├── tests/
└── package.json
在package.json
中,我将"bin"
字段定义为具有"ytpl-export"
属性的对象,其字段为"./source/cli.js"
。这会在终端中注册 ytpl-export
命令,这样它将 运行 我的 CLI 应用程序。
{
"name": "youtube-playlist-export",
"version": "1.0.2",
"engines": {
"node": ">=12"
},
"files": [
"source"
],
"bin": {
"ytpl-export": "./source/cli.js"
}
}
这里是源代码 source/cli.js
:
#!/usr/bin/env node
import c from "chalk";
import { program } from "commander";
import { readPackage } from "read-pkg";
import updateNotifier from "update-notifier";
import idActionHandler from "./commands/id.js";
import keyActionHandler from "./commands/key.js";
import configActionHandler from "./commands/config.js";
(async () => {
const pkg = await readPackage();
updateNotifier({ pkg }).notify();
program.name("ytpl-export").version(pkg.version);
program.addHelpText("before", "Exports video data from a YouTube playlist to JSON/CSV file.\n");
program
.command("id")
.description("Export video metadata of a playlist by its playlist ID.")
.argument(
"<playlistId>",
// prettier-ignore
`The value of the "list" parameter in the the playlist homepage URL (https://www.youtube.com/playlist?list=${c.greenBright("[playlistId]")})`
)
.option("-d, --default", "Skip all questions and use the default config")
.addHelpText(
"after",
`
Example:
$ ytpl-export id PLBCF2DAC6FFB574DE
`
)
.action(idActionHandler);
program.command("key").description("Manage your YouTube API key.").action(keyActionHandler);
program
.command("config")
.description("Edit configurations of this app.")
.option("-p, --path", "show the path of the config file")
.option("-r, --reset", "reset all configurations to default")
.action(configActionHandler);
program.parse(process.argv);
})();
问题原因
感谢Darth的评论,这个问题是由cli.js
中的const pkg = await readPackage();
行引起的:
#!/usr/bin/env node
import { readPackage } from "read-pkg";
/* ... */
(async () => {
const pkg = await readPackage(); // THIS LINE
/* ... */
})();
根据read-pkg
's documentation,如果我们不为readPackage()
提供cwd
选项,cwd
的默认值是process.cwd()
(当前工作目录)。由于我运行 ytpl-export
在主目录下,readPackage()
会尝试读取主目录下的package.json
,它不存在
解决方案
- 安装
get-installed-path
,returns模块安装路径的包到项目:
$ yarn add get-installed-path
- 编辑
cli.js
,使readPackage()
将从安装路径读取package.json
文件:
#!/usr/bin/env node
import { getInstalledPath } from "get-installed-path";
import { readPackage } from "read-pkg";
/* ... */
(async () => {
const installedPath = await getInstalledPath("youtube-playlist-export");
const pkg = await readPackage({ cwd: installedPath });
/* ... */
})();