npm 对于全局安装的CLI应用程序,我应该如何加载package.json?

fcg9iug3  于 2022-12-19  发布在  其他
关注(0)|答案(2)|浏览(150)

我创建了一个cli应用程序,它使用下面的代码从package.json读取其版本号

const packageJson = JSON.parse(fs.readFileSync(path.resolve('./package.json'), 'utf8'))

如果我在开发过程中使用yarn start或类似命令运行应用程序,这可以正常工作。但是在使用npm install --global app-name安装包后,用户应该使用系统上任何路径的declare可执行文件。因此,如果我想在/Users/myUser/Desktop中运行它,我会收到如下错误

Error: ENOENT: no such file or directory, open '/Users/myUser/Desktop/package.json'

那么,在我的CLI中加载这个package.json的好协议是什么呢?或者有没有更好的方法来实现这一点?
稍后编辑:为了清楚起见,我的包json包含以下内容

{
...
"bin": {
    "clip": "./bin/clip.js"
  },
...
}

所以我的问题是指,在使用npm publish之后,从不同的路径运行可执行文件“clip
经过一番研究,我尝试了以下代码(使用path.dirname函数):

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
export const packageJsonLocation = path.join(__dirname, './../package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonLocation, 'utf8'))

和这个(使用node的标准import关键字将文件导入为json)

import * as packageJson from './../package.json' assert { type: 'json' }

在这两种情况下,我得到了相同的结果,生成了可执行文件,并尝试从当前目录读取package.json。特别是,如果我尝试使用console.log()路径,我会得到我正在执行全局可执行文件的当前路径(在我的情况下是clip)

ttisahbt

ttisahbt1#

使用__dirname是因为它总是引用包含此变量的文件的路径,而./提供的是工作目录,例如process.cwd()

const packageJson = JSON.parse(fs.readFileSync(
  path.join(__dirname, 'package.json'), 'utf8')
)

如果您使用ES模块,也要获取__dirname

import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));

const packageJson = JSON.parse(fs.readFileSync(
  path.join(__dirname, 'package.json'), 'utf8')
)

编辑:

您使用bin全局安装了软件包,但使用CLI调用的bin是一个符号链接,位于路径<npm_glob_path>/node_modules/bin内,而不是<npm_glob_path>/node_modules/app-name/bin内。应用的package.json位于<npm_glob_path>/node_modules/app-name内。不要使用./,始终使用path调用
因此,请尝试以下操作(将app-name替换为您的应用名称):

import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url))
console.log('__dirname:' + __dirname) // TELL ME WHAT YOU SEE HERE WHEN YOU RUN THE CLI CMD

const packageJsonLocation = path.join(__dirname, '..', 'app-name' 'package.json')
const packageJson = JSON.parse(fs.readFileSync(
  path.join(__dirname, 'package.json'), 'utf8')
)

请在定义__dirname之后添加console.log('__dirname:' + __dirname)。运行CLI应用程序时,您看到的是哪个路径?

mu0hgdu0

mu0hgdu02#

有没有更好的方法来处理这个问题?
是的-你应该把版本号保存在实际的软件包中,这样它就可以随时访问,并且不会有package.json版本和安装版本不同步的风险。例如,如果有人把你的软件包添加到一个项目中,然后运行yarn install,但后来使用git pull来获取本地文件的最新版本,其中恰好包含您的软件包的版本提升,则会出现一个窗口,其中package.json的版本号与已安装版本不同。

相关问题