Node.js에서 실행되는 javascript에서 NPM 패키지를 설치할 수 있습니까?


92

Node.js에서 실행되는 javascript 파일에서 NPM 패키지를 설치할 수 있습니까? 예를 들어, 스크립트를 갖고 싶습니다. "script.js"라고 부르면 어떻게 든 (... NPM 사용 여부 ...) 일반적으로 NPM을 통해 제공되는 패키지를 설치합니다. 이 예에서는 "FFI"를 설치하고 싶습니다. (npm 설치 ffi)

답변:


110

실제로 npm을 프로그래밍 방식 으로 사용할 수 있으며 이전 버전의 설명서에 설명되어 있습니다. 이후 공식 문서에서 제거되었지만 다음과 같은 내용으로 소스 제어에 여전히 존재합니다.

npm은 프로그래밍 방식으로 사용할 수 있지만 API는 CLI에서만 사용할 수 있으며 다른 목적에 대한 적합성에 대한 보장은 없습니다. npm을 사용하여 일부 작업을 안정적으로 수행하려면 가장 안전한 방법은 적절한 인수를 사용하여 원하는 npm 명령을 호출하는 것입니다.

npm의 시맨틱 버전은 기본 API가 아닌 CLI 자체를 참조합니다. 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) { ... })
})

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먼저 확인하십시오 . 예 훌륭한 :) 작동
mikermcneil

6
또한 조심하십시오- npm많은 종속성이 있으므로 모듈에 추가하면 다운로드하는 데 훨씬 더 오래 걸릴 수 있습니다. child_process사용자 컴퓨터에 이미 설치된 글로벌 npm을 활용 하려면 답변 중 하나를 확인하십시오 .
mikermcneil

1
전달하지 않습니다 npm.confignpm.load! @isaacs조차도 어떤 종류의 이상한 일이 일어날 지 모릅니다! github.com/npm/npm/issues/4861#issuecomment-40533836을 참조하십시오 . 대신 첫 번째 인수를 건너 뛸 수 있습니다.
Georgii Ivankin 2015

2
목적지 경로는 어떻게 설정합니까? (과 다른 경우 process.cwd())
Gajus

1
경고에도 불구하고 NPM을 가져 오려는 경우 global-npm 이 더 좋습니다 (더 작고 종속성 없음)npm install npm --save
Xunnamius

28

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을 실행하고 명령을 수동으로 실행하는 것처럼 전체 출력을 얻을 수있는 모든 답변의 유일한 옵션입니다! 감사합니다!
Jörn Berkefeld

1
무엇을 stdio: [0,1,2]합니까?
Zach Smith

콜백 함수 child_process.exec에 제공되는 경우, 당 [process.stdin, process.stdout, process.stderr] 또는 [0,1,2] 동등한 인자로 호출 API의 의사
krankuba

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

11

실제로 조금 쉬울 수 있습니다.

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

2
이것은 또한 stderr (및 stdout)이 실행이 끝날 때가 아니라 발생하는대로 인쇄된다는 장점이 있습니다!
mvermand

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

3

pacote 는 npm이 패키지 메타 데이터와 타르볼을 가져 오는 데 사용하는 패키지입니다. 안정적인 공개 API가 있습니다.


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로 그것을하고 싶습니다. 이 경우 프로그램을 빌드하는 동안 로컬 node_modules에 NPM을 설치하십시오 ( 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.