Node.js'de çalışan javascript'ten bir NPM paketi yükleyebilir miyim?


93

Node.js'de çalışan bir javascript dosyasından NPM paketi kurabilir miyim? Örneğin, bir betiğe sahip olmak istiyorum, buna "script.js" diyelim ve bir şekilde (... NPM kullanarak ya da kullanmadan ...) genellikle NPM aracılığıyla kullanılabilen bir paket kuralım. Bu örnekte "FFI" yüklemek istiyorum. (npm yükleme ffi)

Yanıtlar:


113

Programlı olarak npm kullanmak gerçekten mümkündür ve dokümantasyonun eski revizyonlarında ana hatları çizilmiştir. O zamandan beri resmi belgelerden kaldırıldı, ancak aşağıdaki ifadeyle hala kaynak kontrolünde var:

Npm programlı olarak kullanılabilse de, API'sı yalnızca CLI tarafından kullanılmak içindir ve başka herhangi bir amaca uygunluğuna ilişkin hiçbir garanti verilmez. Bazı görevleri güvenilir bir şekilde gerçekleştirmek için npm kullanmak istiyorsanız, yapılacak en güvenli şey istenen npm komutunu uygun argümanlarla çağırmaktır.

Npm'nin anlamsal sürümü, temel API'den ziyade CLI'nin kendisine başvurur. Npm'nin sürümü, semver'e göre hiçbir değişiklik yapılmadığını gösterse bile, dahili API'nin kararlı kalması garanti edilmez .

Orijinal belgelerde, sağlanan kod örneği aşağıdadır:

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) { ... })
})

Yana npm var node_modulesklasörde, kullanabileceğiniz require('npm')başka bir modül gibi yüklemek için. Bir modül kurmak için kullanmak isteyeceksiniz npm.commands.install().

Kaynağa bakmanız gerekiyorsa, o da GitHub'da . npm installHerhangi bir komut satırı argümanı olmadan çalıştırmaya eşdeğer kodun eksiksiz bir çalışma örneğini burada bulabilirsiniz :

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

Yükleme işlevinin ilk bağımsız değişkeninin bir dizi olduğuna dikkat edin. Dizinin her bir öğesi, npm'nin kurmaya çalışacağı bir modüldür .

npm-cli.jsKaynak kontrolü dosyasında daha gelişmiş kullanım bulunabilir .


5
Bunun herhangi birine yardımcı olması durumunda - önce yaptığınızdan emin olun npm install npm --save. Örnek harika çalışıyor :)
mikermcneil

6
Ayrıca, dikkatli olun-- npmçok sayıda bağımlılığa sahiptir, bu nedenle onu modülünüze eklemek büyük olasılıkla indirilmesinin ÇOK daha uzun sürmesine neden olacaktır. child_processKullanıcılarınızın makinelerinde zaten yüklü olan global npm'den yararlanmak için yanıtlardan birine göz atın .
mikermcneil

1
Geçmek yok npm.configetmek npm.load! @İsaacs bile o zaman ne tür tuhaf şeyler olacağını bilmiyor! Bkz. Github.com/npm/npm/issues/4861#issuecomment-40533836 Bunun yerine, 1. bağımsız değişkeni atlayabilirsiniz.
Georgii Ivankin

2
Hedef yolu nasıl ayarlarım? (bundan farklı olduğunda process.cwd())
Gajus

1
Uyarılara rağmen NPM'yi içe aktarmak isteyenler için, global-npm daha iyidir (daha küçüktür, bağımlılıkları yoktur)npm install npm --save
Xunnamius

29

Child_process'i kullanabilirsiniz . exec veya execSync bir kabuk oluşturmak için ardından bu kabuk içinde istenen komutu çalıştırarak üretilen herhangi bir çıktıyı tamponlayarak:

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

Bir geri arama işlevi sağlanmışsa, argümanlarla (hata, stdout, stderr) çağrılır. Bu şekilde kurulumu manuel olarak yaptığınız gibi çalıştırabilir ve tam çıktıyı görebilirsiniz.

Child_process.execSync () yöntemi, alt süreç tamamen kapanana kadar yöntemin geri dönmemesi dışında, genellikle child_process.exec () ile aynıdır.


2
bu, örneğin npm kurulumunu çalıştırmanıza ve komutu manüel olarak çalıştırıyormuşsunuz gibi tam çıktı almanıza izin veren tüm yanıtlardan tek seçenektir! teşekkür ederim!
Jörn Berkefeld

1
Ne anlama geliyor stdio: [0,1,2]?
Zach Smith

Bir geri arama işlevi child_process.exec sağlandıysa, o uygun olarak [process.stdin, process.stdout, process.stderr] veya [0,1,2] eşdeğer bağımsız değişken olarak adlandırılır API doc
krankuba

26

Evet. bir sistem komutunu yürütmek için child_process kullanabilirsiniz

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
Evet, ancak bazı bağımlılıklar yüklenemez (deneyime dayanarak konuşursak , çünkü bir zamanlar node.js için bir CI sunucusu yazmıştım)
Matej

5
Pencerelerde bu çalışmıyor! Onun npm.cmdyerine araman gerekiyor .
DUzun

11

aslında biraz kolay olabilir

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

2
Bu aynı zamanda stderr (ve stdout) çalıştırma sonunda değil, ortaya çıktıkça yazdırılır!
mvermand

1
Anlayabildiğim kadarıyla bu, aşağıdaki @ krankuba'dan gelen yanıtla aynı ölçüde yazdırılmıyor.
Zach Smith

6

Bir proje dizininde çalışmak için ilk örneği almaya çalışırken, başka birinin bunu bulması durumunda buraya yazarken çok zaman geçirdim. Anlayabildiğim kadarıyla, NPM hala doğrudan düzgün çalışıyor, ancak CLI'yi varsaydığı için kendimizi biraz kurarken tekrar etmemiz gerekiyor:

// 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'nin paket meta verilerini ve tarball'ları almak için kullandığı pakettir. Kararlı, genel bir API'ye sahiptir.


2

Aklınızdan geçenleri tam olarak yapmanıza izin veren bir modülün yazarıyım. Bkz canlı eklenti-yöneticisi .

NPM, Github veya bir klasörden hemen hemen her paketi kurabilir ve çalıştırabilirsiniz.

İşte bir örnek:

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

Yukarıdaki kodda momentpaketi çalışma zamanında kurar, yükler ve çalıştırırım. Sonunda onu kaldırıyorum.

Dahili olarak npmcli çalıştırmıyorum ama aslında paketleri indiriyorum ve bir düğüm sanal alanı içinde çalıştırıyorum.


1

@Hexacyanide tarafından harika bir çözüm, ancak NPM'nin artık "log" olayı yaymadığı ortaya çıktı (en azından 6.4.1 sürümünden itibaren). Bunun yerine bağımsız bir modül olan https://github.com/npm/npmlog'a güveniyorlar . Neyse ki bu bir singleton, dolayısıyla NPM'nin günlükler için kullandığı aynı örneğe ulaşabilir ve günlük etkinlikleri için abone olabiliriz:

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

  });

Koddan da görebileceğiniz gibi, NPM ayrıca üzerinde performans ölçümleri yayınlar process, böylece ilerlemeyi izlemek için de kullanabiliriz.


1

Burada bahsedilmeyen başka bir seçenek, çatal yapmak ve CLI'yi doğrudan ./node_modules/npm/bin/npm-cli.js

Örneğin, NPM'nin kurulu olmadığı bir makineye komut dosyası çalıştırarak düğüm modüllerini yükleyebilmek istiyorsunuz. Ve bunu CLI ile yapmak İSTİYORSUNUZ. Bu durumda, programınızı oluştururken ( npm i npm) node_modüllerinize yerel olarak NPM'yi kurun .

O zaman şu şekilde kullanın:

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

O zaman programınız, örneğin PKG paketi ile ikili dosyaya bile paketlenebilir . Bu durumda --ignore-scriptsnpm seçeneğini kullanmanız gerekir , çünkü node-gyp önceden yükleme komut dosyalarını çalıştırmak için gereklidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.