Installez les dépendances globalement et localement à l'aide de package.json


189

En utilisant npm, nous pouvons installer les modules globalement en utilisant l' -goption. Comment pouvons-nous faire cela dans le fichier package.json?

Supposons que ce soient mes dépendances dans le fichier package.json

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

Quand je cours npm install, je veux seulement node.ioêtre installé globalement, les autres doivent être installés localement. Y a-t-il une option pour cela?


11
Vous ne pouvez pas. Vous pouvez cependant définir à l' "preferGlobal": trueintérieur de package.json pour un module.
Raynos

ouais, je connais <code> preferGlobal </code>, mais cela installerait toutes les dépendances dans le monde ... de toute façon Merci! Je suppose qu'il n'y a pas de fonctionnalité comme ça ...
Madhusudhan

3
Je ne pense pas que ce soit le cas. Il installe globalement le module actuel. Si une dépendance individuelle a la valeur true, elle peut également être installée globalement. Vraiment, vous devriez simplement demander @isaacs dans # node.js
Raynos

3
Les installations globales peuvent produire un enfer de dépendance. Supposons que le package A nécessite la version 0.3.3 et le package B version 0.3.4 et que les deux ne fonctionnent pas avec l'autre version. Ensuite, vous auriez besoin de deux machines pour accueillir les deux packages.
nalply

6
aucun de ces commentaires ne m'aide avec ce problème ... ce serait bien si vous codiez me montrer plus que juste "preferGlobal":true... je ne sais pas vraiment où mettre cela dans package.json. npmjs.org/doc/json.html La documentation NPM indique que preferGlobal est pour votre propre paquet et que ce paramètre le fera installer votre propre paquet en tant que global. cela ressemble plus à un guide, cependant.
PPPaul

Réponses:


216

Nouvelle note: vous ne voulez probablement pas ou n'avez pas besoin de faire cela. Ce que vous voulez probablement faire, c'est simplement mettre ces types de dépendances de commandes pour build / test, etc. dans la devDependenciessection de votre package.json. Chaque fois que vous utilisez quelque chose de scriptspackage.json, vos commandes devDependencies (dans node_modules / .bin) agissent comme si elles se trouvaient dans votre chemin.

Par exemple:

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

Puis dans package.json:

// devDependencies has mocha and babel now

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

Ensuite, à votre invite de commande, vous pouvez exécuter:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Mais si vous voulez vraiment installer globalement, vous pouvez ajouter une pré-installation dans la section scripts du package.json:

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

Donc en fait mon installation npm exécute à nouveau l'installation de npm .. ce qui est bizarre mais semble fonctionner.

Remarque: vous pouvez rencontrer des problèmes si vous utilisez la configuration la plus courante pour les npmemplacements d'installation du package global Node sudo. Une option consiste à modifier votre npmconfiguration, ce n'est donc pas nécessaire:

npm config set prefix ~/npm, ajoutez $ HOME / npm / bin à $ PATH en ajoutant export PATH=$HOME/npm/bin:$PATHà votre fichier ~/.bashrc.


3
Je n'ai pas réussi à faire fonctionner cela npm i -g underscore-cli. cela donne un avertissement sur le fait que wd se trompe. wd signifie répertoire de travail, je suppose. lorsque je fais cela manuellement sur la ligne de commande, les choses se passent bien, mais je préférerais que l'utilisateur puisse gérer l'installation de mon code avec un simplenpm install
PPPaul

3
PPPaul - J'ai eu le même problème lorsque j'ai réessayé cette astuce récemment. Peut-être que ma configuration est différente maintenant ou qu'elle ne fonctionne qu'avec certains modules. Sinon, je suppose que quelque chose a changé avec npm?
Jason Livesay

9
En plus de cela, vous pouvez pré-vérifier si le package est déjà installé: npm list module -g || npm install module -gas npm renverra les valeurs de sortie appropriées.
m90 le

3
@CMCDragonkai: Cela devrait vraiment être une question distincte. Mais, vous mettez vos commandes dans un script et spécifiez le script comme commande à exécuter (comme "preinstall" : "scripts/preinstall.sh").
Nous sommes tous Monica

1
@CMCDragonkai les concat avec &&, par exemplenpm install -g bower && npm install -g grunt-cli
Matsemann

12

En raison des inconvénients décrits ci-dessous, je recommanderais de suivre la réponse acceptée:

Utilisez npm install --save-dev [package_name]puis exécutez des scripts avec:

$ npm run lint
$ npm run build
$ npm test

Ma réponse originale mais non recommandée suit.


Au lieu d'utiliser une installation globale, vous pouvez ajouter le package à votre devDependencies( --save-dev), puis exécuter le binaire de n'importe où dans votre projet:

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

Dans ton cas:

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

Cet ingénieur a fourni un npm-execalias comme raccourci. Cet ingénieur utilise un shellscript appelé env.sh. Mais je préfère utiliser $(npm bin)directement, pour éviter tout fichier ou configuration supplémentaire.

Bien que cela rend chaque appel un peu plus grand, cela devrait simplement fonctionner , en évitant:

  • conflits de dépendance potentiels avec les packages globaux (@nalply)
  • Le besoin de sudo
  • la nécessité de configurer un préfixe npm (bien que je recommande d'en utiliser un quand même)

Désavantages:

  • $(npm bin) ne fonctionnera pas sous Windows.
  • Les outils plus profondément dans votre arbre de développement n'apparaîtront pas dans le npm bindossier. (Installez npm-run ou npm-which pour les trouver.)

Il semble qu'une meilleure solution consiste à placer les tâches courantes (telles que la construction et la réduction) dans la section "scripts" de votre package.json, comme Jason le montre ci-dessus.


Ajouter un alias dans votre .bashrcajouter facilement le bin/répertoire à votre PATHvariable d'environnement: alias nodebin='export PATH=$(npm bin)/:$PATH'. Exécutez nodebinet vous pouvez simplement taper vos commandes comme d'habitude.
gitaarik

Je ne sais pas pourquoi cela ne fonctionnerait pas pour les équipes. Bien sûr, vous devez le configurer, et si vous n'aimez pas utiliser l'alias, c'est votre choix. Mais ça ne peut pas faire de mal de l'utiliser en équipe.
gitaarik

9

C'est un peu vieux mais je suis tombé sur l'exigence alors voici la solution que j'ai trouvée.

Le problème:

Notre équipe de développement gère de nombreux produits d'application Web .NET que nous migrons vers AngularJS / Bootstrap. VS2010 ne se prête pas facilement aux processus de construction personnalisés et mes développeurs travaillent régulièrement sur plusieurs versions de nos produits. Notre VCS est Subversion (je sais, je sais. J'essaie de passer à Git mais mon équipe marketing embêtante est si exigeante) et une seule solution VS comprendra plusieurs projets distincts. J'avais besoin de mon personnel pour avoir une méthode commune pour initialiser leur environnement de développement sans avoir à installer plusieurs fois les mêmes packages Node (gulp, bower, etc.) sur la même machine.

TL; DR:

  1. Nécessite «npm install» pour installer l'environnement de développement global Node / Bower ainsi que tous les packages requis localement pour un produit .NET.

  2. Les packages globaux ne doivent être installés que s'ils ne sont pas déjà installés.

  3. Les liens locaux vers les packages globaux doivent être créés automatiquement.

La solution:

Nous avons déjà un cadre de développement commun partagé par tous les développeurs et tous les produits, j'ai donc créé un script NodeJS pour installer les packages globaux en cas de besoin et créer les liens locaux. Le script réside dans ".... \ SharedFiles" par rapport au dossier de base du produit:

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

Maintenant, si je veux mettre à jour un outil global pour nos développeurs, je mets à jour l'objet "packages" et j'enregistre le nouveau script. Mes développeurs le vérifient et l'exécutent avec "node npm-setup.js" ou par "npm install" à partir de l'un des produits en cours de développement pour mettre à jour l'environnement global. Le tout prend 5 minutes.

En outre, pour configurer l'environnement d'un nouveau développeur, il doit d'abord installer uniquement NodeJS et GIT pour Windows, redémarrer son ordinateur, consulter le dossier «Fichiers partagés» et tous les produits en cours de développement, et commencer à travailler.

Le "package.json" du produit .NET appelle ce script avant l'installation:

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

Remarques

  • Notez que la référence de script nécessite des barres obliques même dans un environnement Windows.

  • "npm ls" donnera des messages "npm ERR! extraneous:" pour tous les packages liés localement car ils ne sont pas répertoriés dans les "dépendances" de "package.json".

Modifier 29/1/16

Le npm-setup.jsscript mis à jour ci-dessus a été modifié comme suit:

  • Le package "version" dans var packagesest désormais la valeur "package" transmise npm installsur la ligne de commande. Cela a été modifié pour permettre l'installation de packages à partir d'un autre emplacement que le référentiel enregistré.

  • Si le package est déjà installé mais n'est pas celui demandé, le package existant est supprimé et le package correct installé.

  • Pour des raisons inconnues, npm lancera périodiquement une erreur EBUSY (-4082) lors de l'exécution d'une installation ou d'un lien. Cette erreur est interceptée et la commande est réexécutée. L'erreur se produit rarement une deuxième fois et semble toujours disparaître.


C'est une bouée de sauvetage @ sthames42! Je traîne depuis des heures pour essayer de comprendre exactement comment faire cela. Clair, complet, généralement génial. #points Questions: (a) Pourquoi Bower est-il dans la post-installation alors qu'il est déjà dans la liste des packages? (b) Comment ne PAS lier localement les packages globaux? N'incluez simplement pas de "liens" dans la commande?
MaxRocket

@MaxRocket: Heureux d'avoir pu aider. J'ai mis à jour la réponse pour inclure mon dernier qui fonctionne beaucoup mieux. Réponses: (a) la commande 'bower install' s'exécute après que 'npm install' soit terminé pour installer les composants Bower répertoriés dans le fichier bower.json non montré ici. Je voulais que mes collaborateurs puissent taper «npm install» et que leur environnement soit entièrement configuré sans avoir à taper une autre commande. (b) Oui.
sthames42 le

La version actuelle de ce script est maintenant maintenue ici .
sthames42

6

Vous pouvez utiliser un fichier séparé, comme npm_globals.txt, au lieu de package.json. Ce fichier contiendrait chaque module sur une nouvelle ligne comme celle-ci,

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

Ensuite, dans la ligne de commande, exécutez,

< npm_globals.txt xargs npm install -g

Vérifiez qu'ils sont installés correctement avec,

npm list -g --depth=0

Quant à savoir si vous devriez le faire ou non, je pense que tout dépend du cas d'utilisation. Pour la plupart des projets, ce n'est pas nécessaire; et il package.jsonest préférable que votre projet encapsule ces outils et dépendances ensemble.

Mais de nos jours, je constate que j'installe toujours create-react-appet d'autres CLI dans le monde lorsque je saute sur une nouvelle machine. C'est bien d'avoir un moyen simple d'installer un outil global et ses dépendances lorsque la gestion des versions n'a pas beaucoup d'importance.

Et de nos jours, j'utilise npx, un coureur de package npm , au lieu d'installer des packages globalement.


3

Tous les modules de package.json sont installés dans ./node_modules/

Je n'ai pas pu trouver cela explicitement indiqué, mais c'est la référence package.json pour NPM .


1

Créez votre propre script pour installer les dépendances globales. Il n'en faut pas beaucoup. package.json est assez extensible.

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

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

En utilisant ce qui précède, vous pouvez même le faire en ligne, ci-dessous!

Regardez la préinstallation ci-dessous:

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

Les auteurs de node peuvent ne pas admettre que package.json est un fichier projet. Mais il est.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.