Node.js: Get (absolute) root path of installed npm package

前端 未结 2 1385
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-12 05:54

Task

I\'m looking for an universal way to get the (absolute) root path of an installed npm package in Node.js.

Problem

I know about require

2条回答
  •  不要未来只要你来
    2021-01-12 06:58

    you don't need to look up the desired package's package.json file, or even refer to its location explicitly.

    moreover, you shouldn't do it, as there is no sure way to know where will that npm package end up in npm's tree (which is why you turned to require.resolve for help).

    instead, you can query the npm API (or CLI) by using npm ls with the --parseable flag, which will:

    Show parseable output instead of tree view.

    for example:

    $ npm ls my-dep -p
    

    … will output something like this:

    /Users/me/my-project/node_modules/my-dep
    

    you should be aware that this command can output some irrelevant errors as well to stderr (e.g. about extraneous installations) — to work around this, activate the --silent flag (see loglevel in the docs):

    $ npm ls my-dep -ps
    

    this command can be integrated into your code using a child process, in which case it's preferred to run the command without the --silent flag to allow capturing any error.

    if an error is catched, you can then decide whether its fatal or not (e.g. the aforementioned error about extraneous package should be ignored).

    so usage of the CLI via a child process can look like this:

    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
        }
    });
    

    this can then be used (along with some closure magic…) in an async flow, e.g.:

    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());
            });
        };
    }
    

提交回复
热议问题