任务
我正在寻找一种通用方法来获取Node.js中已安装的npm包的(绝对)根路径 .
问题
我知道 require.resolve
,但这会给我一个入口点(主模块的路径)而不是包的根路径 .
以 bootstrap-sass
为例 . 假设它在本地安装在项目文件夹 C:\dev\my-project
中 . 然后我要找的是 C:\dev\my-project\node_modules\bootstrap-sass
. require.resolve('bootstrap-sass')
将返回 C:\dev\my-project\node_modules\bootstrap-sass\assets\javascripts\bootstrap.js
.
我可以想到几种方法如何获取包的根路径:
解决方案#1
var packageRoot = path.resolve('node_modules/bootstrap-sass');
console.log(packageRoot);
这适用于在 node_modules
文件夹中本地安装的软件包 . 但是,如果我在子文件夹中,我需要解决 ../node_modules/bootstrap-sass
,并且使用更多嵌套文件夹会更复杂 . 此外,这不适用于全局安装的模块 .
解决方案#2
var packageRoot = require.resolve('bootstrap-sass')
.match(/^.*[\/\\]node_modules[\/\\][^\/\\]*/)[0];
console.log(packageRoot);
这适用于安装在 node_modules
文件夹中的本地和全局模块 . 正则表达式将匹配最后一个 node_modules
路径元素以及以下路径元素的所有内容 . 但是,如果将包的入口点设置为另一个包(例如 package.json
中的 "main": "./node_modules/sub-package"
),则此操作将失败 .
解决方案#3
var escapeStringRegexp = require('escape-string-regexp');
/**
* Get the root path of a npm package installed in node_modules.
* @param {string} packageName The name of the package.
* @returns {string} Root path of the package without trailing slash.
* @throws Will throw an error if the package root path cannot be resolved
*/
function packageRootPath(packageName) {
var mainModulePath = require.resolve(packageName);
var escapedPackageName = escapeStringRegexp(packageName);
var regexpStr = '^.*[\\/\\\\]node_modules[\\/\\\\]' + escapedPackageName +
'(?=[\\/\\\\])';
var rootPath = mainModulePath.match(regexpStr);
if (rootPath) {
return rootPath[0];
} else {
var msg = 'Could not resolve package root path for package `' +
packageName + '`.'
throw new Error(msg);
}
}
var packageRoot = packageRootPath('bootstrap-sass');
console.log(packageRoot);
此功能适用于安装在 node_modules
文件夹中的所有软件包 .
但......
我想知道这个相当简单的任务是否不能以更简单,更少的黑客方式解决 . 对我而言,它看起来应该已经构建到Node.js中 . 有什么建议?
2 回答
您不需要查找所需包的package.json文件,甚至不需要显式引用它的位置 .
此外,你不应该这样做,因为没有确定的方法知道npm包将在npm的树中结束(这就是为什么你转向
require.resolve
寻求帮助) .相反,您可以使用带有--parseable标志的npm ls查询npm API(或CLI),它将:
例如:
...将输出如下内容:
你应该知道这个命令可以输出一些不相关的错误以及stderr(例如关于无关安装) - 要解决这个问题,激活
--silent
标志(参见文档中的loglevel):可以使用child process将此命令集成到您的代码中,在这种情况下,首选运行不带
--silent
标志的命令以允许捕获任何错误 .如果捕获了错误,则可以判断其是否致命(例如上述关于无关包的错误应该被忽略) .
因此,通过子进程使用CLI可能如下所示:
然后可以在异步流中使用它(以及一些封闭魔法......),例如:
试试这个:
返回:
你现在可以摆脱'package.json'路径后缀,例如:
由于每个包都必须包含
package.json
文件,因此应始终有效(请参阅What is a package?) .