Instal dependensi secara global dan lokal menggunakan package.json

189

Menggunakan npm kita dapat menginstal modul secara global menggunakan -gopsi. Bagaimana kita bisa melakukan ini di file package.json?

Misalkan, ini adalah dependensi saya dalam file package.json

"dependencies": {
    "mongoose": "1.4.0",
    "node.io" : "0.3.3",
    "jquery"  : "1.5.1",
    "jsdom"   : "0.2.0",
    "cron"    : "0.1.2"
  }

Ketika saya menjalankan npm install, saya hanya ingin node.iodiinstal secara global, sisanya harus diinstal secara lokal. Apakah ada opsi untuk ini?

Madhusudhan
sumber
11
Kamu tidak bisa Namun Anda dapat mengatur "preferGlobal": truedi dalam package.json untuk modul.
Raynos
ya, saya tahu tentang <code> preferGlobal </code>, tapi itu akan menginstal semua dependensi secara global ... tetap terima kasih! saya kira tidak ada fitur seperti itu ...
Madhusudhan
3
Saya kira tidak. Itu menginstal modul saat ini secara global. Jika ketergantungan individu telah disetel ke true, itu juga dapat diinstal secara global. Sungguh, Anda sebaiknya bertanya pada @isaacs di # node.js
Raynos
3
Instalasi global dapat menghasilkan neraka ketergantungan. Katakan paket A membutuhkan versi 0.3.3 dan paket B versi 0.3.4 dan keduanya tidak berfungsi dengan versi lainnya. Maka Anda akan membutuhkan dua mesin untuk mengakomodasi dua paket.
nalply
6
tidak ada komentar ini yang membantu saya dengan masalah ini ... alangkah baiknya jika Anda menunjukkan kode lebih dari sekadar "preferGlobal":true... saya tidak benar-benar tahu di mana harus meletakkan ini di package.json. npmjs.org/doc/json.html Dokumentasi NPM mengatakan bahwa preferGlobal adalah untuk paket Anda sendiri dan pengaturan itu akan membuatnya menginstal paket Anda sendiri sebagai global. sepertinya lebih dari panduan.
PPPaul

Jawaban:

216

Catatan Baru: Anda mungkin tidak ingin atau perlu melakukan ini. Apa yang Anda mungkin ingin lakukan adalah hanya menempatkan jenis-jenis dependensi perintah untuk build / test dll di devDependenciesbagian package.json Anda. Setiap kali Anda menggunakan sesuatu dari scriptsdalam package.json perintah devDependencies Anda (dalam node_modules / .bin) bertindak seolah-olah mereka berada di jalur Anda.

Sebagai contoh:

npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally

Kemudian di package.json:

// devDependencies has mocha and babel now

"scripts": {
  "test": "mocha",
  "build": "babel -d lib src",
  "prepublish": "babel -d lib src"
}

Kemudian pada command prompt Anda, Anda dapat menjalankan:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Tetapi jika Anda benar - benar ingin menginstal secara global, Anda dapat menambahkan pra-instal di bagian skrip dari package.json:

"scripts": {
  "preinstall": "npm i -g themodule"
}

Jadi sebenarnya instal npm saya mengeksekusi instal npm lagi .. yang aneh tapi sepertinya berfungsi.

Catatan: Anda mungkin memiliki masalah jika Anda menggunakan pengaturan paling umum untuk npmtempat paket Node global diinstal sudo. Salah satu opsi adalah mengubah npmkonfigurasi Anda jadi ini tidak perlu:

npm config set prefix ~/npm, tambahkan $ HOME / npm / bin ke $ PATH dengan menambahkan export PATH=$HOME/npm/bin:$PATHke ~/.bashrc.

Jason Livesay
sumber
3
Saya tidak bisa menyelesaikannya npm i -g underscore-cli. itu memberi peringatan tentang kesalahan. wd berarti direktori yang berfungsi, saya kira. ketika saya secara manual melakukan ini pada baris perintah maka semuanya berjalan dengan baik, namun saya lebih suka jika pengguna dapat menangani menginstal kode saya dengan sederhananpm install
PPPaul
3
PPPaul - Saya memiliki masalah yang sama ketika saya mencoba trik ini lagi baru-baru ini. Mungkin setup saya berbeda sekarang atau hanya berfungsi dengan modul tertentu. Kalau tidak, saya kira sesuatu berubah dengan npm?
Jason Livesay
9
Selain itu, Anda dapat melakukan pra-periksa apakah paket sudah diinstal: npm list module -g || npm install module -gkarena npm akan mengembalikan nilai keluar yang tepat.
m90
3
@ CMCDragonkai: Ini benar-benar harus menjadi pertanyaan terpisah. Tapi, Anda menempatkan perintah dalam skrip, dan menentukan skrip sebagai perintah untuk dieksekusi (seperti "preinstall" : "scripts/preinstall.sh").
We Are All Monica
1
@CMCDragonkai menyapa mereka &&, misalnyanpm install -g bower && npm install -g grunt-cli
Matsemann
12

Karena kerugian yang dijelaskan di bawah ini, saya akan merekomendasikan mengikuti jawaban yang diterima:

Gunakan npm install --save-dev [package_name]kemudian jalankan skrip dengan:

$ npm run lint
$ npm run build
$ npm test

Jawaban asli saya tetapi tidak disarankan berikut.


Alih-alih menggunakan instalasi global, Anda bisa menambahkan paket ke devDependencies( --save-dev) Anda dan kemudian menjalankan biner dari mana saja di dalam proyek Anda:

"$(npm bin)/<executable_name>" <arguments>...

Dalam kasus Anda:

"$(npm bin)"/node.io --help

Insinyur ini menyediakan npm-execalias sebagai pintasan. Insinyur ini menggunakan shellscript bernama env.sh. Tapi saya lebih suka menggunakan $(npm bin)secara langsung, untuk menghindari file atau pengaturan tambahan.

Meskipun itu membuat setiap panggilan sedikit lebih besar, itu hanya akan berfungsi , mencegah:

  • potensi konflik ketergantungan dengan paket global (@nalply)
  • kebutuhan untuk sudo
  • kebutuhan untuk mengatur awalan npm (meskipun saya sarankan tetap menggunakannya)

Kekurangan:

  • $(npm bin) tidak akan berfungsi di Windows.
  • Alat yang lebih dalam di pohon dev Anda tidak akan muncul di npm binfolder. (Instal npm-run atau npm-yang untuk menemukannya.)

Tampaknya solusi yang lebih baik adalah menempatkan tugas-tugas umum (seperti membangun dan mengecilkan) di bagian "skrip" Anda package.json, seperti yang diperlihatkan Jason di atas.

joeytwiddle
sumber
Menambahkan alias di Anda .bashrcuntuk dengan mudah menambahkan bin/direktori untuk Anda PATHvariabel lingkungan: alias nodebin='export PATH=$(npm bin)/:$PATH'. Jalankan nodebindan kemudian Anda bisa mengetik perintah Anda seperti biasa.
gitaarik
Saya tidak tahu mengapa itu tidak bekerja untuk tim. Tentu saja Anda perlu mengaturnya, dan jika Anda tidak suka menggunakan alias itu pilihan Anda. Tetapi tidak ada salahnya untuk menggunakannya dalam tim.
gitaarik
9

Ini agak tua tapi saya berlari ke persyaratan jadi di sini adalah solusi yang saya buat.

Masalah:

Tim pengembang kami mengelola banyak produk aplikasi web .NET yang kami migrasi ke AngularJS / Bootstrap. VS2010 tidak cocok dengan proses pembuatan kustom dan pengembang saya secara rutin bekerja pada beberapa rilis produk kami. VCS kami adalah Subversion (saya tahu, saya tahu. Saya sedang mencoba untuk pindah ke Git tetapi staf pemasaran saya sangat menuntut) dan solusi VS tunggal akan mencakup beberapa proyek terpisah. Saya membutuhkan staf saya untuk memiliki metode umum untuk menginisialisasi lingkungan pengembangan mereka tanpa harus menginstal paket Node yang sama (tegukan, bower, dll.) Beberapa kali pada mesin yang sama.

TL; DR:

  1. Perlu "npm install" untuk menginstal lingkungan pengembangan Node / Bower global serta semua paket yang diperlukan secara lokal untuk produk .NET.

  2. Paket global harus diinstal hanya jika belum diinstal.

  3. Tautan lokal ke paket global harus dibuat secara otomatis.

Solusinya:

Kami sudah memiliki kerangka pengembangan bersama yang dibagikan oleh semua pengembang dan semua produk, jadi saya membuat skrip NodeJS untuk menginstal paket global bila diperlukan dan membuat tautan lokal. Script berada di ".... \ SharedFiles" relatif terhadap folder basis produk:

/*******************************************************************************
* $Id: npm-setup.js 12785 2016-01-29 16:34:49Z sthames $
* ==============================================================================
* Parameters: 'links' - Create links in local environment, optional.
* 
* <p>NodeJS script to install common development environment packages in global
* environment. <c>packages</c> object contains list of packages to install.</p>
* 
* <p>Including 'links' creates links in local environment to global packages.</p>
* 
* <p><b>npm ls -g --json</b> command is run to provide the current list of 
* global packages for comparison to required packages. Packages are installed 
* only if not installed. If the package is installed but is not the required 
* package version, the existing package is removed and the required package is 
* installed.</p>.
*
* <p>When provided as a "preinstall" script in a "package.json" file, the "npm
* install" command calls this to verify global dependencies are installed.</p>
*******************************************************************************/
var exec = require('child_process').exec;
var fs   = require('fs');
var path = require('path');

/*---------------------------------------------------------------*/
/* List of packages to install and 'from' value to pass to 'npm  */
/* install'. Value must match the 'from' field in 'npm ls -json' */
/* so this script will recognize a package is already installed. */
/*---------------------------------------------------------------*/
var packages = 
  {
  "bower"                      :                      "[email protected]", 
  "event-stream"               :               "[email protected]",
  "gulp"                       :                       "[email protected]",
  "gulp-angular-templatecache" : "[email protected]",
  "gulp-clean"                 :                 "[email protected]", 
  "gulp-concat"                :                "[email protected]",
  "gulp-debug"                 :                 "[email protected]",
  "gulp-filter"                :                "[email protected]",
  "gulp-grep-contents"         :         "[email protected]",
  "gulp-if"                    :                    "[email protected]", 
  "gulp-inject"                :                "[email protected]", 
  "gulp-minify-css"            :            "[email protected]",
  "gulp-minify-html"           :           "[email protected]",
  "gulp-minify-inline"         :         "[email protected]",
  "gulp-ng-annotate"           :           "[email protected]",
  "gulp-processhtml"           :           "[email protected]",
  "gulp-rev"                   :                   "[email protected]",
  "gulp-rev-replace"           :           "[email protected]",
  "gulp-uglify"                :                "[email protected]",
  "gulp-useref"                :                "[email protected]",
  "gulp-util"                  :                  "[email protected]",
  "lazypipe"                   :                   "[email protected]",
  "q"                          :                          "[email protected]",
  "through2"                   :                   "[email protected]",

  /*---------------------------------------------------------------*/
  /* fork of 0.2.14 allows passing parameters to main-bower-files. */
  /*---------------------------------------------------------------*/
  "bower-main"                 : "git+https://github.com/Pyo25/bower-main.git" 
  }

/*******************************************************************************
* run */
/**
* Executes <c>cmd</c> in the shell and calls <c>cb</c> on success. Error aborts.
* 
* Note: Error code -4082 is EBUSY error which is sometimes thrown by npm for 
* reasons unknown. Possibly this is due to antivirus program scanning the file 
* but it sometimes happens in cases where an antivirus program does not explain 
* it. The error generally will not happen a second time so this method will call 
* itself to try the command again if the EBUSY error occurs.
* 
* @param  cmd  Command to execute.
* @param  cb   Method to call on success. Text returned from stdout is input.
*******************************************************************************/
var run = function(cmd, cb)
  {
  /*---------------------------------------------*/
  /* Increase the maxBuffer to 10MB for commands */
  /* with a lot of output. This is not necessary */
  /* with spawn but it has other issues.         */
  /*---------------------------------------------*/
  exec(cmd, { maxBuffer: 1000*1024 }, function(err, stdout)
    {
    if      (!err)                   cb(stdout);
    else if (err.code | 0 == -4082) run(cmd, cb);
    else throw err;
    });
  };

/*******************************************************************************
* runCommand */
/**
* Logs the command and calls <c>run</c>.
*******************************************************************************/
var runCommand = function(cmd, cb)
  {
  console.log(cmd);
  run(cmd, cb);
  }

/*******************************************************************************
* Main line
*******************************************************************************/
var doLinks  = (process.argv[2] || "").toLowerCase() == 'links';
var names    = Object.keys(packages);
var name;
var installed;
var links;

/*------------------------------------------*/
/* Get the list of installed packages for   */
/* version comparison and install packages. */
/*------------------------------------------*/
console.log('Configuring global Node environment...')
run('npm ls -g --json', function(stdout)
  {
  installed = JSON.parse(stdout).dependencies || {};
  doWhile();
  });

/*--------------------------------------------*/
/* Start of asynchronous package installation */
/* loop. Do until all packages installed.     */
/*--------------------------------------------*/
var doWhile = function()
  {
  if (name = names.shift())
    doWhile0();
  }

var doWhile0 = function()
  {
  /*----------------------------------------------*/
  /* Installed package specification comes from   */
  /* 'from' field of installed packages. Required */
  /* specification comes from the packages list.  */
  /*----------------------------------------------*/
  var current  = (installed[name] || {}).from;
  var required =   packages[name];

  /*---------------------------------------*/
  /* Install the package if not installed. */
  /*---------------------------------------*/
  if (!current)
    runCommand('npm install -g '+required, doWhile1);

  /*------------------------------------*/
  /* If the installed version does not  */
  /* match, uninstall and then install. */
  /*------------------------------------*/
  else if (current != required)
    {
    delete installed[name];
    runCommand('npm remove -g '+name, function() 
      {
      runCommand('npm remove '+name, doWhile0);
      });
    }

  /*------------------------------------*/
  /* Skip package if already installed. */
  /*------------------------------------*/
  else
    doWhile1();
  };

var doWhile1 = function()
  {
  /*-------------------------------------------------------*/
  /* Create link to global package from local environment. */
  /*-------------------------------------------------------*/
  if (doLinks && !fs.existsSync(path.join('node_modules', name)))
    runCommand('npm link '+name, doWhile);
  else
    doWhile();
  };

Sekarang jika saya ingin memperbarui alat global untuk pengembang kami, saya memperbarui objek "paket" dan memeriksa skrip baru. Pengembang saya memeriksanya dan menjalankannya dengan "node npm-setup.js" atau dengan "npm install" dari salah satu produk yang sedang dikembangkan untuk memperbarui lingkungan global. Semuanya membutuhkan waktu 5 menit.

Selain itu, untuk mengonfigurasi lingkungan untuk pengembang baru, mereka harus terlebih dahulu hanya menginstal NodeJS dan GIT untuk Windows, reboot komputer mereka, periksa folder "File Bersama" dan produk apa pun yang sedang dikembangkan, dan mulai bekerja.

"Package.json" untuk produk .NET memanggil skrip ini sebelum menginstal:

{ 
"name"                    : "Books",
"description"             : "Node (npm) configuration for Books Database Web Application Tools",
"version"                 : "2.1.1",
"private"                 : true,
"scripts":
  {
  "preinstall"            : "node ../../SharedFiles/npm-setup.js links",
  "postinstall"           : "bower install"
  },
"dependencies": {}
}

Catatan

  • Perhatikan referensi skrip memerlukan garis miring maju bahkan di lingkungan Windows.

  • "npm ls" akan memberikan "npm ERR! extraneous:" pesan untuk semua paket yang terhubung secara lokal karena mereka tidak terdaftar dalam "package.json" "dependensi".

Edit 1/29/16

npm-setup.jsSkrip yang diperbarui di atas telah dimodifikasi sebagai berikut:

  • Paket "versi" di var packagessekarang menjadi nilai "paket" yang diteruskan ke npm installbaris perintah. Ini diubah untuk memungkinkan menginstal paket dari tempat lain selain dari repositori terdaftar.

  • Jika paket sudah diinstal tetapi bukan yang diminta, paket yang ada dihapus dan yang benar diinstal.

  • Untuk alasan yang tidak diketahui, npm akan secara berkala melempar kesalahan EBUSY (-4082) saat melakukan pemasangan atau tautan. Kesalahan ini terjebak dan perintah dijalankan kembali. Kesalahan jarang terjadi untuk kedua kalinya dan sepertinya selalu beres.

sthames42
sumber
Ini adalah penyelamat @ sthames42! Saya sudah berjam-jam mencoba mencari tahu bagaimana melakukan ini. Jelas, komprehensif, umumnya luar biasa. Pertanyaan #points: (a) Mengapa Bower berada di postinstall ketika sudah ada dalam daftar paket? (B) Bagaimana TIDAK secara lokal menghubungkan paket global? Hanya saja, jangan menyertakan "tautan" dalam perintah?
MaxRocket
@ MaxRocket: Senang saya bisa membantu. Saya telah memperbarui jawaban untuk memasukkan yang terbaru yang berfungsi lebih baik. Jawaban: (a) perintah 'bower install' berjalan setelah 'npm install' dilakukan untuk menginstal komponen Bower yang tercantum dalam file bower.json yang tidak ditampilkan di sini. Saya ingin orang-orang saya dapat mengetik 'npm install' dan mengatur lingkungan mereka tanpa harus mengetik perintah lain. (b) Ya.
sthames42
Versi skrip ini sekarang dipertahankan di sini .
sthames42
6

Anda dapat menggunakan file terpisah, seperti npm_globals.txt, bukan package.json. File ini akan berisi setiap modul pada baris baru seperti ini,

mongoose@1.4.0
node.io@0.3.3
jquery@1.5.1
jsdom@0.2.0
cron@0.1.2

Kemudian di baris perintah jalankan,

< npm_globals.txt xargs npm install -g

Pastikan mereka diinstal dengan benar,

npm list -g --depth=0

Adapun apakah Anda harus melakukan ini atau tidak, saya pikir itu semua tergantung pada use case. Untuk sebagian besar proyek, ini tidak perlu; dan memiliki proyek Anda package.jsonmerangkum alat-alat ini dan dependensi bersama lebih disukai.

Tetapi saat ini saya menemukan bahwa saya selalu menginstal create-react-appdan CLI lain secara global ketika saya menggunakan mesin baru. Sangat menyenangkan memiliki cara mudah untuk menginstal alat global dan dependensinya ketika versi tidak terlalu penting.

Dan saat ini, saya menggunakan npx , pelari paket npm , bukannya menginstal paket secara global.

Atav32
sumber
3

Semua modul dari package.json diinstal ke ./node_modules/

Saya tidak dapat menemukan ini secara eksplisit tetapi ini adalah referensi package.json untuk NPM .

nibblebot
sumber
1

Buat skrip Anda sendiri untuk menginstal dependensi global. Tidak butuh banyak. package.json cukup diperluas.

const {execSync} = require('child_process');

JSON.parse(fs.readFileSync('package.json'))
     .globalDependencies.foreach(
         globaldep => execSync('npm i -g ' + globaldep)
     );

Dengan menggunakan di atas, Anda bahkan dapat membuatnya sejajar, di bawah!

Lihat pra-instal di bawah ini:

{
  "name": "Project Name",
  "version": "0.1.0",
  "description": "Project Description",
  "main": "app.js",
  "scripts": {
    "preinstall": "node -e \"const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.foreach(globaldep => execSync('npm i -g ' + globaldep));\"",
    "build": "your transpile/compile script",
    "start": "node app.js",
    "test": "./node_modules/.bin/mocha --reporter spec",
    "patch-release": "npm version patch && npm publish && git add . && git commit -m \"auto-commit\" && git push --follow-tags"
  },
  "dependencies": [
  },
  "globalDependencies": [
    "[email protected]",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

Penulis simpul mungkin tidak mengakui package.json adalah file proyek. Tapi itu benar.

TamusJRoyce
sumber