我可以从Node.js中运行的javascript文件安装NPM包吗?例如,我想要一个脚本,让我们称它为“script.js”,不知何故(......使用NPM或不...)安装一个通常可以通过NPM获得的包。在这个例子中,我想安装“FFI”。 (npm install ffi)
答案 0 :(得分:97)
确实可以以编程方式使用 npm ,并且在文档的旧版本中概述了它。它已从官方文档中删除,但仍然存在于源代码管理中,并带有以下声明:
虽然npm可以通过编程方式使用,但它的API可供使用 仅限CLI,并且不保证其适用于任何 其他目的。如果你想使用npm来可靠地执行某些任务, 最安全的做法是使用调用所需的npm命令 适当的论点。
npm的语义版本是指CLI本身,而不是 底层API。 内部API无法保证稳定 即使npm的版本表明没有进行任何重大更改 根据semver 。
在原始文档中,以下是提供的代码示例:
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')
像任何其他模块一样加载它。要安装模块,您需要使用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);
});
});
请注意,install函数的第一个参数是一个数组。数组的每个元素都是 npm 将尝试安装的模块。
可以在源代码管理的npm-cli.js
文件中找到更高级的用法。
答案 1 :(得分:22)
是肯定的。您可以使用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);
}
});
答案 2 :(得分:17)
如果您想要输出,也可以使用:
var child_process = require('child_process');
child_process.execSync("npm install ffi",{stdio:[0,1,2]});
通过这种方式,您可以像手头一样观看安装,避免出现意外错误(缓冲区已满等)
答案 3 :(得分:8)
它实际上可能有点容易
var exec = require('child_process').exec;
child = exec('npm install ffi').stderr.pipe(process.stderr);
答案 4 :(得分:3)
我有一段时间试图让第一个例子在项目目录中工作,发布在这里以防其他人发现这个。据我所知,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);
});
});
答案 5 :(得分:1)
我是一个模块的作者,可以让你完全按照自己的想法行事。 请参阅live-plugin-manager。
您可以从NPM,Github或文件夹中安装和运行几乎任何软件包。
这是一个例子:
import {PluginManager} from "live-plugin-manager";
const manager = new PluginManager();
async function run() {
await manager.install("moment");
const moment = manager.require("moment");
console.log(moment().format());
await manager.uninstall("moment");
}
run();
在上面的代码中,我在运行时安装moment
包,加载并执行它。最后我卸载它。
在内部我不会运行npm
cli,但实际下载包并在节点VM沙箱中运行。
答案 6 :(得分:0)
pacote是npm用于获取软件包元数据和tarball的软件包。它具有稳定的公共API。
答案 7 :(得分:0)
@hexacyanide的一个很好的解决方案,但事实证明NPM不再发出“ log”事件(至少从6.4.1版开始)。相反,它们依赖于独立模块https://github.com/npm/npmlog。幸运的是,这是一个单例,因此我们可以达到NPM用于日志并订阅日志事件的相同实例:
const npmlog = require( "npm/node_modules/npmlog" ),
npm = require( "npm" );
npmlog.on( "log", msg => {
console.log({ msg });
});
process.on("time", milestone => {
console.log({ milestone });
});
process.on("timeEnd", milestone => {
console.log({ milestone });
});
npm.load({
loaded: false,
progress: false,
"no-audit": true
}, ( err ) => {
npm.commands.install( installDirectory, [
"cross-env@^5.2.0",
"shelljs@^0.8.2"
], ( err, data ) => {
console.log( "done" );
});
});
从代码中可以看到,NPM还会在process
上发出性能指标,因此我们也可以使用它来监视进度。
答案 8 :(得分:0)
此处未提及的另一个选项是直接从./node_modules/npm/bin/npm-cli.js
进行派生并运行CLI
例如,您希望能够通过未安装NPM的计算机上的运行脚本来安装节点模块。而且您确实想使用CLI做到这一点。在这种情况下,只需在构建程序(npm i npm
)时在本地node_modules中安装NPM。
然后像这样使用它:
// Require child_process module
const { fork } = require('child_process');
// Working directory for subprocess of installer
const cwd = './path-where-to-run-npm-command';
// CLI path FROM cwd path! Pay attention
// here - path should be FROM your cwd directory
// to your locally installed npm module
const cli = '../node_modules/npm/bin/npm-cli.js';
// NPM arguments to run with
// If your working directory already contains
// package.json file, then just install it!
const args = ['install']; // Or, i.e ['audit', 'fix']
// Run installer
const installer = fork(cli, args, {
silent: true,
cwd: cwd
});
// Monitor your installer STDOUT and STDERR
installer.stdout.on('data', (data) => {
console.log(data);
});
installer.stderr.on('data', (data) => {
console.log(data);
});
// Do something on installer exit
installer.on('exit', (code) => {
console.log(`Installer process finished with code ${code}`);
});
然后,您的程序甚至可以打包为二进制文件,例如使用PKG软件包。在这种情况下,您需要使用--ignore-scripts
npm选项,因为node-gyp需要运行预安装脚本