Installa le dipendenze a livello globale e locale usando package.json


189

Usando npm possiamo installare i moduli a livello globale usando l' -gopzione. Come possiamo farlo nel file package.json?

Supponiamo che queste siano le mie dipendenze nel 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"
  }

Quando corro npm install, voglio solo node.ioessere installato a livello globale, il resto dovrebbe essere installato localmente. C'è un'opzione per questo?


11
Non puoi. Puoi comunque impostare "preferGlobal": truedentro package.json per un modulo.
Raynos,

sì, so di <code> preferGlobal </code>, ma questo installerebbe tutte le dipendenze a livello globale ... comunque Grazie! immagino che non ci sia nessuna caratteristica del genere ...
Madhusudhan,

3
Non credo. Installa il modulo corrente a livello globale. Se una singola dipendenza è impostata su true, può anche essere installata a livello globale. In realtà si dovrebbe solo chiedere @isaacs in # node.js
Raynos

3
Le installazioni globali possono produrre inferno di dipendenza. Dire che il pacchetto A richiede la versione 0.3.3 e il pacchetto B versione 0.3.4 ed entrambi non funzionano con l'altra versione. Quindi avresti bisogno di due macchine per accogliere i due pacchetti.
nalply

6
nessuno di questi commenti mi aiuta a risolvere questo problema ... sarebbe bello se il codice mi mostrasse più di un semplice "preferGlobal":true... non so davvero dove inserirlo in package.json. npmjs.org/doc/json.html La documentazione di NPM afferma che preferGlobal è per il tuo pacchetto e che l'impostazione lo farà installare il tuo pacchetto come globale. sembra più una guida, però.
PPPaul,

Risposte:


216

Nuova nota: probabilmente non vuoi o non devi farlo. Quello che probabilmente vuoi fare è semplicemente mettere quei tipi di dipendenze di comando per build / test ecc. Nella devDependenciessezione di package.json. Ogni volta che usi qualcosa da scriptsin package.json i tuoi comandi devDependencies (in node_modules / .bin) si comportano come se fossero nel tuo percorso.

Per esempio:

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

Quindi in package.json:

// devDependencies has mocha and babel now

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

Quindi al prompt dei comandi è possibile eseguire:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Ma se vuoi davvero installare globalmente, puoi aggiungere una preinstallazione nella sezione script di package.json:

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

Quindi in realtà la mia installazione di npm esegue di nuovo l'installazione di npm .. che è strano ma sembra funzionare.

Nota: è possibile che si verifichino problemi se si utilizza l'installazione più comune per la npmquale sono richieste installazioni di pacchetti di nodi globali sudo. Un'opzione è modificare la npmconfigurazione, quindi non è necessario:

npm config set prefix ~/npm, aggiungi $ HOME / npm / bin a $ PATH aggiungendo export PATH=$HOME/npm/bin:$PATHal tuo ~/.bashrc.


3
Non sono riuscito a farlo funzionare npm i -g underscore-cli. dà un avvertimento sul fatto che wd ha torto. wd significa directory di lavoro, immagino. quando lo faccio manualmente sulla riga di comando, le cose vanno bene, tuttavia preferirei che l'utente fosse in grado di gestire l'installazione del mio codice con un semplicenpm install
PPPaul

3
PPPaul - Ho avuto lo stesso problema quando ho provato di nuovo questo trucco di recente. Forse la mia configurazione è diversa ora o funziona solo con determinati moduli. Altrimenti immagino che qualcosa sia cambiato con npm?
Jason Livesay,

9
Inoltre, è possibile verificare preventivamente se il pacchetto è già installato: npm list module -g || npm install module -gpoiché npm restituirà i valori di uscita corretti.
m90

3
@CMCDragonkai: questa dovrebbe essere davvero una domanda separata. Ma metti i tuoi comandi in uno script e specifichi lo script come comando da eseguire (come "preinstall" : "scripts/preinstall.sh").
Siamo tutti Monica il

1
@CMCDragonkai li contatta &&, ad esempionpm install -g bower && npm install -g grunt-cli
Matsemann il

12

A causa degli svantaggi descritti di seguito, consiglierei di seguire la risposta accettata:

Utilizzare npm install --save-dev [package_name]quindi eseguire gli script con:

$ npm run lint
$ npm run build
$ npm test

Segue la mia risposta originale ma non raccomandata .


Invece di utilizzare un'installazione globale, è possibile aggiungere il pacchetto a your devDependencies( --save-dev) e quindi eseguire il file binario da qualsiasi punto all'interno del progetto:

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

Nel tuo caso:

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

Questo ingegnere ha fornito un npm-execalias come scorciatoia. Questo ingegnere usa uno shellscript chiamato env.sh. Ma preferisco usare $(npm bin)direttamente, per evitare qualsiasi file aggiuntivo o installazione.

Anche se rende ogni chiamata un po 'più grande, dovrebbe funzionare , impedendo:

  • potenziali conflitti di dipendenza con pacchetti globali (@nalply)
  • il bisogno di sudo
  • la necessità di impostare un prefisso npm (anche se consiglio comunque di usarne uno)

svantaggi:

  • $(npm bin) non funzionerà su Windows.
  • Gli strumenti più profondi nella struttura degli sviluppatori non verranno visualizzati nella npm bincartella. (Installa npm-run o npm-che li trovi).

Sembra che una soluzione migliore sia quella di inserire attività comuni (come costruire e minimizzare) nella sezione "script" del tuo package.json, come Jason dimostra sopra.


Aggiungere un alias nel .bashrcdi aggiungere facilmente la bin/directory alla PATHvariabile d'ambiente: alias nodebin='export PATH=$(npm bin)/:$PATH'. Esegui nodebine quindi puoi semplicemente digitare i tuoi comandi come al solito.
Gitaarik,

Non so perché non funzionerebbe per i team. Ovviamente devi configurarlo, e se non ti piace usare l'alias questa è la tua scelta. Ma non può far male usarlo in una squadra.
Gitaarik,

9

Questo è un po 'vecchio ma ho incontrato il requisito, quindi ecco la soluzione che ho trovato.

Il problema:

Il nostro team di sviluppo mantiene molti prodotti di applicazioni Web .NET che stiamo migrando verso AngularJS / Bootstrap. VS2010 non si presta facilmente ai processi di creazione personalizzati e i miei sviluppatori lavorano abitualmente su più versioni dei nostri prodotti. Il nostro VCS è Subversion (lo so, lo so. Sto cercando di passare a Git ma il mio fastidioso personale di marketing è così esigente) e una singola soluzione VS includerà diversi progetti separati. Avevo bisogno che il mio personale avesse un metodo comune per inizializzare il proprio ambiente di sviluppo senza dover installare più volte gli stessi pacchetti Nodo (gulp, bower, ecc.) Sulla stessa macchina.

TL; DR:

  1. È necessario "npm install" per installare l'ambiente di sviluppo globale Node / Bower e tutti i pacchetti richiesti localmente per un prodotto .NET.

  2. I pacchetti globali dovrebbero essere installati solo se non sono già installati.

  3. I collegamenti locali ai pacchetti globali devono essere creati automaticamente.

La soluzione:

Abbiamo già un framework di sviluppo comune condiviso da tutti gli sviluppatori e tutti i prodotti, quindi ho creato uno script NodeJS per installare i pacchetti globali quando necessario e creare i collegamenti locali. Lo script risiede in ".... \ SharedFiles" relativo alla cartella di base del prodotto:

/*******************************************************************************
* $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"                      :                      "bower@1.7.2", 
  "event-stream"               :               "event-stream@3.3.2",
  "gulp"                       :                       "gulp@3.9.0",
  "gulp-angular-templatecache" : "gulp-angular-templatecache@1.8.0",
  "gulp-clean"                 :                 "gulp-clean@0.3.1", 
  "gulp-concat"                :                "gulp-concat@2.6.0",
  "gulp-debug"                 :                 "gulp-debug@2.1.2",
  "gulp-filter"                :                "gulp-filter@3.0.1",
  "gulp-grep-contents"         :         "gulp-grep-contents@0.0.1",
  "gulp-if"                    :                    "gulp-if@2.0.0", 
  "gulp-inject"                :                "gulp-inject@3.0.0", 
  "gulp-minify-css"            :            "gulp-minify-css@1.2.3",
  "gulp-minify-html"           :           "gulp-minify-html@1.0.5",
  "gulp-minify-inline"         :         "gulp-minify-inline@0.1.1",
  "gulp-ng-annotate"           :           "gulp-ng-annotate@1.1.0",
  "gulp-processhtml"           :           "gulp-processhtml@1.1.0",
  "gulp-rev"                   :                   "gulp-rev@6.0.1",
  "gulp-rev-replace"           :           "gulp-rev-replace@0.4.3",
  "gulp-uglify"                :                "gulp-uglify@1.5.1",
  "gulp-useref"                :                "gulp-useref@3.0.4",
  "gulp-util"                  :                  "gulp-util@3.0.7",
  "lazypipe"                   :                   "lazypipe@1.0.1",
  "q"                          :                          "q@1.4.1",
  "through2"                   :                   "through2@2.0.0",

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

Ora, se voglio aggiornare uno strumento globale per i nostri sviluppatori, aggiorno l'oggetto "pacchetti" e controllo il nuovo script. I miei sviluppatori lo verificano e lo eseguono con "node npm-setup.js" o con "npm install" da uno dei prodotti in sviluppo per aggiornare l'ambiente globale. Il tutto richiede 5 minuti.

Inoltre, per configurare l'ambiente per un nuovo sviluppatore, devono prima installare solo NodeJS e GIT per Windows, riavviare il computer, controllare la cartella "File condivisi" e tutti i prodotti in fase di sviluppo e iniziare a lavorare.

"Package.json" per il prodotto .NET chiama questo script prima dell'installazione:

{ 
"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": {}
}

Appunti

  • Nota che il riferimento allo script richiede barre rovesciate anche in ambiente Windows.

  • "npm ls" restituirà "npm ERR! estraneo:" messaggi per tutti i pacchetti collegati localmente perché non sono elencati nelle "dipendenze" di "package.json".

Modifica 1/29/16

Lo npm-setup.jsscript aggiornato sopra è stato modificato come segue:

  • Il pacchetto "versione" in var packagesè ora il valore "pacchetto" passato alla npm installriga di comando. Questo è stato modificato per consentire l'installazione di pacchetti da un posto diverso dal repository registrato.

  • Se il pacchetto è già installato ma non è quello richiesto, il pacchetto esistente viene rimosso e quello corretto installato.

  • Per motivi sconosciuti, npm genererà periodicamente un errore EBUSY (-4082) quando si esegue un'installazione o un collegamento. Questo errore viene intercettato e il comando viene rieseguito. L'errore si verifica raramente una seconda volta e sembra sempre chiarire.


Questo è un vero toccasana @ sthames42! Ho trollato per ore cercando di capire esattamente come farlo. Chiaro, completo, generalmente fantastico. #points Domande: (a) Perché Bower è nella postinstallazione quando è già nella lista dei pacchetti? (b) Come NON collegare localmente i pacchetti globali? Basta non includere "collegamenti" nel comando?
MaxRocket

@MaxRocket: Sono contento di aver potuto aiutare. Ho aggiornato la risposta per includere la mia ultima che funziona molto meglio. Risposte: (a) il comando 'bower install' viene eseguito dopo 'npm install' per installare i componenti Bower elencati nel file bower.json non mostrato qui. Volevo che il mio personale fosse in grado di digitare 'npm install' e che il suo ambiente fosse completamente impostato senza dover digitare un altro comando. (b) Sì.
sthames42,

La versione corrente di questo script è ora mantenuta qui .
sthames42,

6

È possibile utilizzare un file separato, come npm_globals.txt, invece di package.json. Questo file conterrebbe ogni modulo su una nuova riga come questa,

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

Quindi, nella riga di comando, esegui

< npm_globals.txt xargs npm install -g

Verifica che siano installati correttamente con,

npm list -g --depth=0

Per quanto riguarda se dovresti farlo o no, penso che tutto dipenda dal caso d'uso. Per la maggior parte dei progetti, questo non è necessario; e avere il tuo progetto package.jsonincapsulare questi strumenti e dipendenze insieme è molto preferito.

Ma al giorno d'oggi trovo che installo sempre create-react-appe altre CLI a livello globale quando salgo su una nuova macchina. È bello avere un modo semplice per installare uno strumento globale e le sue dipendenze quando il controllo delle versioni non ha molta importanza.

E al giorno d'oggi, sto usando npx, un pacchetto corridore NPM , invece di installare pacchetti a livello globale.


3

Tutti i moduli da package.json sono installati in ./node_modules/

Non sono riuscito a trovarlo esplicitamente, ma questo è il riferimento package.json per NPM .


1

Crea il tuo script per installare dipendenze globali. Non ci vuole molto. package.json è abbastanza espandibile.

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

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

Usando quanto sopra, puoi persino renderlo in linea, sotto!

Guarda preinstallato di seguito:

{
  "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": [
    "cordova@8.1.2",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

Gli autori di node potrebbero non ammettere package.json è un file di progetto. Ma è.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.