web-dev-qa-db-fra.com

Installer des dépendances globalement et localement en utilisant package.json

Avec npm, nous pouvons installer les modules globalement en utilisant l’option -g. 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 lance npm install, je veux que seul node.io soit installé globalement, les autres doivent être installés localement. Y a-t-il une option pour cela?

178
Madhusudhan

Nouvelle note: Vous ne voulez probablement pas ou n'avez pas besoin de le faire. Ce que vous voulez probablement faire est simplement de mettre ces types de dépendances de commande pour build/test, etc. dans la section devDependencies de votre package.json. Chaque fois que vous utilisez quelque chose de scripts dans package.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, à l'invite de votre 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 de package.json:

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

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

Remarque: vous pourriez avoir des problèmes si vous utilisez la configuration la plus courante pour npm où le paquet global Node installe le package requis Sudo. Une option consiste à modifier votre configuration npm afin que cela ne soit pas nécessaire:

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

206
Jason Livesay

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 les scripts avec:

$ npm run lint
$ npm run build
$ npm test

Ma réponse d'origine mais n'est pas recommandée suit.


Au lieu d'utiliser une installation globale, vous pouvez ajouter le package à votre devDependencies (--save-dev), puis exécuter le binaire à partir 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 alias npm-exec comme raccourci. Cet ingénieur utilise un script de shell appelé env.sh. Mais je préfère utiliser $(npm bin) directement, pour éviter tout fichier ou configuration supplémentaire.

Bien que chaque appel soit un peu plus volumineux, il devrait simplement fonctionner , en empêchant:

  • 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 vous recommande néanmoins d'en utiliser un)

Désavantages:

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

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

12
joeytwiddle

C'est un peu vieux mais j'ai rencontré l'exigence alors voici la solution que j'ai proposé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 personnel de marketing embêtant est si exigeant) et une solution unique de VS comportera plusieurs projets distincts. J'avais besoin que mon personnel dispose d'une méthode commune pour initialiser son environnement de développement sans avoir à installer plusieurs fois le même Node packages (gulp, bower, etc.) sur le même ordinateur.

TL; DR:

  1. Vous avez besoin de "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 disposons déjà d'un framework 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"                      :                      "[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();
  };

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

En outre, pour configurer l'environnement pour un nouveau développeur, ils doivent d'abord installer NodeJS et GIT pour Windows, redémarrer leur ordinateur, consulter le dossier "Fichiers partagés" et tous les produits en développement, puis commencer à fonctionner.

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

Notes

  • 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 "package.json" "dépendances".

Edit 29/01/16

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

  • Le package "version" dans var packages est maintenant la valeur "package" transmise à npm install sur la ligne de commande. Cela a été modifié pour permettre l'installation de packages à partir d'un emplacement autre 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 correct installé.

  • Pour des raisons inconnues, npm génère périodiquement une erreur EBUSY (-4082) lors de l'installation ou de la liaison. Cette erreur est interceptée et la commande réexécutée. L'erreur se produit rarement une seconde fois et semble toujours disparaître.

9
sthames42

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

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

Ensuite, dans la ligne de commande,

< npm_globals.txt xargs npm install -g

Vérifiez qu'ils sont correctement installés 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, cela n'est pas nécessaire. et il est préférable que package.json de votre projet encapsule ces outils et dépendances.

Mais de nos jours, je constate que je suis toujours en train d'installer create-react-app et d'autres CLI globalement lorsque je saute sur une nouvelle machine. C'est bien d'avoir un moyen facile d'installer un outil global et ses dépendances lorsque le versioning n'a pas beaucoup d'importance.

Et de nos jours, j'utilise npx , n programme d'exécution de paquets npm , au lieu d'installer des packages globalement.

4
Atav32

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

Je ne trouvais pas cela explicitement indiqué, mais c’est la référence package.json pour NPM .

4
nibblebot

Construisez votre propre script pour installer des dépendances globales. Ça ne prend 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 rendre 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": [
    "[email protected]",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

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

0
TamusJRoyce