我可以从在 Node.js 中运行的 javascript 安装 NPM 包吗?

IT技术 javascript node.js npm
2021-03-09 04:20:32

我可以从在 Node.js 中运行的 javascript 文件安装 NPM 包吗?例如,我想要一个脚本,我们称之为“script.js”,它以某种方式(...使用 NPM 或不...)安装通常可通过 NPM 获得的包。在这个例子中,我想安装“FFI”。(npm 安装 ffi)

6个回答

确实可以以编程方式使用npm,并且在文档的较旧修订版中对其进行了概述。它已从官方文档中删除,但仍然存在于源代码控制中,并带有以下声明:

尽管 npm 可以以编程方式使用,但其 API 仅供 CLI 使用,并且不保证其适用于任何其他目的。如果您想使用 npm 可靠地执行某些任务,最安全的做法是使用适当的参数调用所需的 npm 命令。

npm 的语义版本指的是 CLI 本身,而不是底层 API。即使 npm 的版本表明没有根据 semver 进行重大更改,内部 API 也不能保证保持稳定

在原始文档中,以下是提供的代码示例:

var npm = require('npm')
npm.load(myConfigObject, function (er) {
  if (er) return handlError(er)
  npm.commands.install(['some', 'args'], function (er, data) {
    if (er) return commandFailed(er)
    // command succeeded, and data might have some info
  })
  npm.registry.log.on('log', function (message) { ... })
})

由于npm存在于node_modules文件夹中,因此您可以require('npm')像加载任何其他module一样使用它。要安装module,您需要使用npm.commands.install().

如果您需要查看源代码,那么它也在GitHub 上这是代码的完整工作示例,相当于在npm install没有任何命令行参数的情况下运行

var npm = require('npm');
npm.load(function(err) {
  // handle errors

  // install module ffi
  npm.commands.install(['ffi'], function(er, data) {
    // log errors or data
  });

  npm.on('log', function(message) {
    // log installation progress
    console.log(message);
  });
});

请注意,安装函数的第一个参数是一个数组。数组的每个元素都是一个npm将尝试安装的module

更高级的用法可以npm-cli.js在源代码管理文件中找到

万一这对任何人有帮助 - 确保你先做npm install npm --save示例效果很好:)
2021-04-15 04:20:32
对于那些尽管有警告但希望导入 NPM 的人来说,global-npmnpm install npm --save
2021-04-15 04:20:32
千万不要错过npm.confignpm.load连@isaacs 都不知道会发生什么样的怪事!请参阅github.com/npm/npm/issues/4861#issuecomment-40533836相反,您可以跳过第一个参数。
2021-04-18 04:20:32
另外,请注意 -npm有很多依赖项,因此将其添加到您的module中很可能会导致下载时间更长。查看child_process答案之一以利用已安装在用户计算机上的全局 npm。
2021-04-21 04:20:32
如何设置目标路径?(当它不同时process.cwd()
2021-04-30 04:20:32

您可以使用child_processexecexecSync生成一个 shell,然后在该 shell 中执行所需的命令,缓冲任何生成的输出:

var child_process = require('child_process');
child_process.execSync('npm install ffi',{stdio:[0,1,2]});

如果提供了回调函数,则使用参数(错误、标准输出、标准错误)调用它。通过这种方式,您可以像手动操作一样运行安装并查看完整输出。

child_process.execSync() 方法通常与 child_process.exec() 相同,不同之处在于该方法在子进程完全关闭之前不会返回。

有什么作用stdio: [0,1,2]
2021-04-18 04:20:32
如果向 child_process.exec 提供回调函数,则根据api doc 使用与 [process.stdin, process.stdout, process.stderr] 或 [0,1,2] 等效的参数调用它
2021-04-26 04:20:32
这是所有答案中的唯一选项,例如让您运行 npm install 并获得完整输出,就像您手动执行命令一样!谢谢!
2021-04-28 04:20:32

是的。您可以使用 child_process 来执行系统命令

var exec = require('child_process').exec,
    child;

 child = exec('npm install ffi',
 function (error, stdout, stderr) {
     console.log('stdout: ' + stdout);
     console.log('stderr: ' + stderr);
     if (error !== null) {
          console.log('exec error: ' + error);
     }
 });
在 Windows 上这不起作用!你必须打电话npm.cmd
2021-05-05 04:20:32
是的,您可以,但是某些依赖项将无法安装(根据经验,因为从前我实际上为 node.js编写了一个CI服务器)
2021-05-08 04:20:32

它实际上可能有点容易

var exec = require('child_process').exec;
child = exec('npm install ffi').stderr.pipe(process.stderr);
据我所知,这与下面@krankuba 的答案的打印程度不同。
2021-05-04 04:20:32
这还有一个优点,即 stderr(和 stdout)在它们发生时打印,而不是在执行结束时打印!
2021-05-10 04:20:32

我花了很多时间试图让第一个示例在项目目录中工作,并在此处发布以防其他人发现它。据我所知,直接加载 NPM 仍然可以正常工作,但是因为它假设了 CLI,所以我们必须重复自己的设置:

// this must come before load to set your project directory
var previous = process.cwd();
process.chdir(project);

// this is the part missing from the example above
var conf = {'bin-links': false, verbose: true, prefix: project}

// this is all mostly the same

var cli = require('npm');
cli.load(conf, (err) => {
    // handle errors
    if(err) {
        return reject(err);
    }

    // install module
    cli.commands.install(['ffi'], (er, data) => {
        process.chdir(previous);
        if(err) {
            reject(err);
        }
        // log errors or data
        resolve(data);
    });

    cli.on('log', (message) => {
        // log installation progress
        console.log(message);
    });
});
这是一个使用 npm 的示例v7.5.2github.com/probot/create-probot-app/blob/...
2021-04-17 04:20:32
似乎这已经改变了npm >v7.xcommands.install不再遵循process.chdir行为,强制cli.prefix = <myDestinationFolder>内部cli.load回调似乎可以解决它(尽管可能有更好的方法,但我还没有找到)
2021-04-18 04:20:32