x-r*_*ray 7 javascript path package node.js npm
我正在寻找一种通用方法来获取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
.
我可以想到几种方法如何获取包的根路径:
var packageRoot = path.resolve('node_modules/bootstrap-sass');
console.log(packageRoot);
Run Code Online (Sandbox Code Playgroud)
这适用于本地安装在node_modules
文件夹中的软件包.但是,如果我在子文件夹中,我需要解决../node_modules/bootstrap-sass
,并且使用更多嵌套文件夹会变得更复杂.此外,这不适用于全局安装的模块.
var packageRoot = require.resolve('bootstrap-sass')
.match(/^.*[\/\\]node_modules[\/\\][^\/\\]*/)[0];
console.log(packageRoot);
Run Code Online (Sandbox Code Playgroud)
这适用于安装在node_modules
文件夹中的本地和全局模块.正则表达式将匹配最后一个node_modules
路径元素以及以下路径元素的所有内容.但是,如果将包的入口点设置为另一个包(例如,"main": "./node_modules/sub-package"
in package.json
),则会失败.
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);
Run Code Online (Sandbox Code Playgroud)
此功能应适用于node_modules
文件夹中安装的所有包.
我想知道这个相当简单的任务是否不能以更简单,更少的黑客方式解决.对我而言,它看起来应该已经构建到Node.js中.有什么建议?
试试这个:
require.resolve('bootstrap-sass/package.json')
Run Code Online (Sandbox Code Playgroud)
返回:
path_to_my_project/node_modules/bootstrap-sass/package.json
Run Code Online (Sandbox Code Playgroud)
你现在可以摆脱'package.json'路径后缀,例如:
var path = require('path') // npm install path
var bootstrapPath = path.dirname(require.resolve('bootstrap-sass/package.json'))
Run Code Online (Sandbox Code Playgroud)
由于每个包都必须包含package.json
文件,因此应始终有效(请参阅什么是包?).
您不需要查找所需包的 package.json 文件,甚至不需要显式引用其位置。
此外,您不应该这样做,因为没有确定的方法可以知道该 npm 包最终会出现在 npm 树中的何处(这就是您寻求require.resolve
帮助的原因)。
npm ls
相反,您可以使用with标志来查询 npm API(或 CLI)--parseable
,这将:
显示可解析的输出而不是树视图。
例如:
$ npm ls my-dep -p
Run Code Online (Sandbox Code Playgroud)
...将输出类似这样的内容:
/Users/me/my-project/node_modules/my-dep
Run Code Online (Sandbox Code Playgroud)
你应该知道这个命令也可以向 stderr 输出一些不相关的错误(例如关于无关的安装)——要解决这个问题,请激活该--silent
标志(请参阅loglevel
文档):
$ npm ls my-dep -ps
Run Code Online (Sandbox Code Playgroud)
可以使用子进程将此命令集成到您的代码中,在这种情况下,最好运行不带--silent
标志的命令以允许捕获任何错误。
如果捕获到错误,您可以决定其是否致命(例如,应忽略上述有关无关包的错误)。
因此通过子进程使用 CLI 可以如下所示:
const exec = require('child_process').exec;
const packageName = 'my-dep';
exec(`npm ls ${packageName} --parseable`, (err, stdout, stderr) => {
if (!err) {
console.log(stdout.trim()); // -> /Users/me/my-project/node_modules/my-dep
}
});
Run Code Online (Sandbox Code Playgroud)
然后可以在异步流程中使用它(以及一些闭包魔法......),例如:
const exec = require('child_process').exec;
const async = require('async');
async.waterfall([
npmPackagePathResolver('my-dep'),
(packagePath, callback) => {
console.log(packagePath) // -> /Users/me/my-project/node_modules/my-dep
callback();
}
], (err, results) => console.log('all done!'));
function npmPackagePathResolver(packageName) {
return (callback) => {
exec(`npm ls ${packageName} --parseable`, (err, stdout, stderr) => {
callback(err, stdout.trim());
});
};
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3349 次 |
最近记录: |