Node.jsで実行されているJavaScriptからNPMパッケージをインストールできますか?


91

Node.jsで実行されているJavaScriptファイルからNPMパッケージをインストールできますか?たとえば、スクリプトを作成したいのですが、 "script.js"と呼びましょう。NPMを介して通常利用できるパッケージを(NPMを使用するかどうかを問わず)インストールします。この例では、「FFI」をインストールします。(npm install ffi)

回答:


109

プログラムでnpmを使用することは確かに可能であり、ドキュメントの古いリビジョンで概説されていました。それ以降、公式ドキュメントから削除されましたが、次のステートメントでソース管理にまだ存在しています。

npmはプログラムで使用できますが、そのAPIはCLIでの使用のみを目的としており、他の目的への適合性については保証されません。npmを使用していくつかのタスクを確実に実行する場合、最も安全な方法は、適切な引数を使用して目的のnpmコマンドを呼び出すことです。

npmのセマンティックバージョンは、基盤となるAPIではなく、CLI自体を指します。semverによると、npmのバージョンが重大な変更が加えられていないことを示している場合でも、内部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) { ... })
})

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

インストール関数の最初の引数は配列であることに注意してください。配列の各要素は、npmがインストールしようとするモジュールです。

npm-cli.jsソース管理のファイルで、より高度な使用法を見つけることができます。


5
これが誰かを助ける場合に備えて- npm install npm --save最初に行うことを確認してください。例はうまく
いきます

6
また、注意しnpmてください-依存関係がたくさんあるので、モジュールに追加すると、ダウンロードにかなり時間がかかる可能性があります。child_processユーザーのマシンにすでにインストールされているグローバルnpmを活用するための回答の1つを確認してください。
mikermcneil 2013

1
合格しないでくださいnpm.confignpm.load!@isaacsでさえ、そのときどんな種類の奇妙なことが起こるかわかりません!github.com/npm/npm/issues/4861#issuecomment-40533836を参照してください代わりに、最初の引数をスキップすることができます。
Georgii Ivankin 2015

2
宛先パスを設定するにはどうすればよいですか?(それとは異なる場合process.cwd()
Gajus

1
警告にもかかわらずNPMをインポートしたい場合、global-npmnpm install npm --save
Xunnamius

26

はい。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
はい、ただし、一部の依存関係はインストールに失敗します(経験から言うと、たまにnode.js用のCIサーバーを実際に作成したためです)
Matej

5
Windowsではこれは機能しません。npm.cmd代わりに電話する必要があります。
DUzun 2016

26

child_processを使用できます。execまたはexecSyncを実行してシェルを生成し、そのシェル内で目的のコマンドを実行して、生成された出力をバッファリングします。

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

コールバック関数が提供されている場合は、引数(error、stdout、stderr)を指定して呼び出されます。このようにして、手動でインストールを実行し、完全な出力を確認することができます。

child_process.execSync()メソッドは、子プロセスが完全に閉じるまでメソッドが返らないことを除いて、通常はchild_process.exec()と同じです。


2
これは、たとえば、コマンドを手動で実行しているかのように、npm installを実行して完全な出力を取得できるすべての回答からの唯一のオプションです!ありがとうございました!
ジョーンBerkefeld

1
何をしstdio: [0,1,2]ますか?
Zach Smith

コールバック関数がchild_process.execに提供されている場合、APIドキュメント
krankuba

11

実際には少し簡単かもしれません

var exec = require('child_process').exec;
child = exec('npm install ffi').stderr.pipe(process.stderr);

2
これには、実行の終わりではなく、発生時にstderr(およびstdout)が出力されるという利点もあります。
mvermand 2017年

1
これは、私が知る限り、以下の@krankubaからの回答と同じ程度には出力されません。
Zach Smith

6

私は、最初の例をプロジェクトディレクトリ内で動作させるために、他の誰かがこれを見つけた場合に備えて、ここに投稿することにかなりの時間を費やしました。私の知る限り、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);
    });
});


2

私は、あなたが心に描いていることを正確に実行できるモジュールの作者です。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、実行時にパッケージをインストールし、ロードして実行します。最後にアンインストールします。

内部的にはnpmcliを実行しませんが、実際にはパッケージをダウンロードしてノードVMサンドボックス内で実行します。


1

@hexacyanideによる優れたソリューションですが、NPMが「ログ」イベントを発行しないことが判明しました(少なくともバージョン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ため、これを使用して進行状況を監視することもできます。


1

ここで言及されていない別のオプションは、フォークを実行してCLIを直接実行することです ./node_modules/npm/bin/npm-cli.js

たとえば、NPMがインストールされていないマシンでスクリプトを実行してノードモジュールをインストールできるようにしたいとします。そして、あなたはCLIでそれをしたいのです。この場合、プログラムをビルドするときに、NPMをnode_modulesにローカルにインストールするだけnpm i 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、プレインストールスクリプトを実行するにはnode-gypが必要であるため、npmオプションを使用する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.