Instale dependências globalmente e localmente usando package.json


189

Usando o npm, podemos instalar os módulos globalmente usando a -gopção Como podemos fazer isso no arquivo package.json?

Suponha, essas são minhas dependências no arquivo 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 eu executo npm install, quero apenas node.ioser instalado globalmente, o restante deve ser instalado localmente. Existe uma opção para isso?


11
Você não pode. No entanto, você pode definir "preferGlobal": truedentro de package.json para um módulo.
Raynos

sim, eu sei sobre <code> preferGlobal </code>, mas isso instalaria todas as dependências globalmente ... de qualquer maneira Obrigado! eu acho que não há nenhum recurso assim ...
Madhusudhan

3
Eu acho que não. Ele instala o módulo atual globalmente. Se uma dependência individual tiver definido como true, ela também poderá ser instalada globalmente. Realmente você deve apenas pedir @isaacs em # node.js
Raynos

3
Instalações globais podem produzir um inferno de dependência. Diga que o pacote A precisa da versão 0.3.3 e o pacote B versão 0.3.4 e ambos não funcionam com a outra versão. Então você precisaria de duas máquinas para acomodar os dois pacotes.
nalply

6
nenhum desses comentários me ajuda com esse problema ... seria bom se o código me mostrasse mais do que apenas "preferGlobal":true... eu realmente não sei onde colocar isso no package.json. npmjs.org/doc/json.html A documentação do NPM diz que preferGlobal é para seu próprio pacote e essa configuração fará com que você instale seu próprio pacote como global. parece mais um guia, no entanto.
PPPaul

Respostas:


216

Nova nota: você provavelmente não quer ou precisa fazer isso. O que você provavelmente quer fazer é apenas colocar esses tipos de dependências de comando para compilar / testar etc. na devDependenciesseção do seu package.json. Sempre que você usa algo do scriptspackage.json, os comandos devDependencies (em node_modules / .bin) agem como se estivessem no seu caminho.

Por exemplo:

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

Em seguida, em package.json:

// devDependencies has mocha and babel now

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

Em seguida, no prompt de comando, você pode executar:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Mas se você realmente deseja instalar globalmente, pode adicionar uma pré-instalação na seção de scripts do pacote.json:

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

Então, na verdade, o meu npm install executa o npm install novamente .. o que é estranho, mas parece funcionar.

Nota: você pode ter problemas se estiver usando a configuração mais comum para npmonde o pacote global do Node é necessário sudo. Uma opção é alterar sua npmconfiguração para que isso não seja necessário:

npm config set prefix ~/npm, adicione $ HOME / npm / bin a $ PATH, anexando export PATH=$HOME/npm/bin:$PATHao seu ~/.bashrc.


3
Não consegui fazer isso funcionar npm i -g underscore-cli. emite um aviso sobre a wd estar errada. wd significa diretório de trabalho, eu acho. quando eu manualmente fazer isso na linha de comando, em seguida, as coisas vão bem, no entanto Eu preferiria se o usuário fosse capaz de lidar com a instalação meu código com um simplesnpm install
PPPaul

3
PPPaul - Eu tive o mesmo problema quando tentei esse truque recentemente recentemente. Talvez minha configuração seja diferente agora ou funcione apenas com determinados módulos. Caso contrário, acho que algo mudou com o npm?
precisa

9
Além disso, você pode verificar previamente se o pacote já está instalado: npm list module -g || npm install module -go npm retornará os valores de saída adequados.
M90

3
@CMCDragonkai: Esta deve realmente ser uma pergunta separada. Mas, você coloca seus comandos em um script e especifica o script como o comando a ser executado (como "preinstall" : "scripts/preinstall.sh").
Somos Todos Monica

1
@CMCDragonkai os concatena com &&, por exemplonpm install -g bower && npm install -g grunt-cli
Matsemann

12

Devido às desvantagens descritas abaixo, eu recomendaria seguir a resposta aceita:

Use npm install --save-dev [package_name]e execute scripts com:

$ npm run lint
$ npm run build
$ npm test

Minha resposta original, mas não recomendada, segue.


Em vez de usar uma instalação global, você pode adicionar o pacote ao seu devDependencies( --save-dev) e depois executar o binário de qualquer lugar dentro do seu projeto:

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

No seu caso:

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

Este engenheiro forneceu um npm-execalias como atalho. Este engenheiro usa um shellscript chamado env.sh. Mas eu prefiro usar $(npm bin)diretamente, para evitar qualquer arquivo ou configuração extra.

Embora torne cada chamada um pouco maior, deve funcionar , impedindo:

  • conflitos de dependência em potencial com pacotes globais (@nalply)
  • a necessidade de sudo
  • a necessidade de configurar um prefixo npm (apesar de eu recomendar o uso de qualquer maneira)

Desvantagens:

  • $(npm bin) não funcionará no Windows.
  • Ferramentas mais profundas na sua árvore de desenvolvimento não aparecerão na npm binpasta. (Instale npm-run ou npm-which para encontrá-los.)

Parece que uma solução melhor é colocar tarefas comuns (como compilar e minificar) na seção "scripts" do seu package.json, como Jason demonstra acima.


Adicionar um alias em sua .bashrcfacilmente adicionar o bin/diretório a sua PATHvariável de ambiente: alias nodebin='export PATH=$(npm bin)/:$PATH'. Execute nodebine, em seguida, você pode apenas digitar seus comandos, como de costume.
Gitaarik

Não sei por que não funcionaria para equipes. Claro que você precisa configurá-lo e, se você não gosta de usar o alias, é sua escolha. Mas não custa nada usá-lo em equipe.
Gitaarik

9

Isso é um pouco antigo, mas me deparei com o requisito, então aqui está a solução que eu criei.

O problema:

Nossa equipe de desenvolvimento mantém muitos produtos de aplicativos da Web .NET que estamos migrando para o AngularJS / Bootstrap. O VS2010 não se presta facilmente a processos de criação personalizados e meus desenvolvedores estão trabalhando rotineiramente em várias versões de nossos produtos. Nosso VCS é o Subversion (eu sei, eu sei. Estou tentando mudar para o Git, mas minha péssima equipe de marketing é muito exigente) e uma única solução de VS incluirá vários projetos separados. Eu precisava que minha equipe tivesse um método comum para inicializar seu ambiente de desenvolvimento sem precisar instalar os mesmos pacotes Node (gulp, bower etc.) várias vezes na mesma máquina.

TL; DR:

  1. É necessário "npm install" para instalar o ambiente de desenvolvimento global do Node / Bower, bem como todos os pacotes necessários localmente para um produto .NET.

  2. Pacotes globais devem ser instalados apenas se ainda não estiverem instalados.

  3. Links locais para pacotes globais devem ser criados automaticamente.

A solução:

Já temos uma estrutura de desenvolvimento comum compartilhada por todos os desenvolvedores e todos os produtos, por isso criei um script NodeJS para instalar os pacotes globais quando necessário e criar os links locais. O script reside em ".... \ SharedFiles" relativo à pasta base do produto:

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

Agora, se eu quiser atualizar uma ferramenta global para nossos desenvolvedores, atualizo o objeto "packages" e faço check-in no novo script. Meus desenvolvedores fazem check-out e executam-no com "node npm-setup.js" ou por "npm install" de qualquer um dos produtos em desenvolvimento para atualizar o ambiente global. A coisa toda leva 5 minutos.

Além disso, para configurar o ambiente para um novo desenvolvedor, primeiro é necessário instalar o NodeJS e o GIT for Windows, reiniciar o computador, verificar a pasta "Arquivos compartilhados" e todos os produtos em desenvolvimento e começar a trabalhar.

O "package.json" para o produto .NET chama esse script antes da instalação:

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

Notas

  • Observe que a referência de script requer barras, mesmo em um ambiente Windows.

  • "npm ls" dará "npm ERR! estranhas:" mensagens para todos os pacotes vinculados localmente porque não estão listados nas "dependências" "package.json".

Editar 29/1/16

O npm-setup.jsscript atualizado acima foi modificado da seguinte maneira:

  • O pacote "version" in var packagesagora é o valor do "package" passado para npm installa linha de comando. Isso foi alterado para permitir a instalação de pacotes de algum lugar que não seja o repositório registrado.

  • Se o pacote já estiver instalado, mas não o solicitado, o pacote existente será removido e o pacote correto, instalado.

  • Por motivos desconhecidos, o npm lançará periodicamente um erro EBUSY (-4082) ao executar uma instalação ou link. Este erro está interceptado e o comando é executado novamente. O erro raramente acontece uma segunda vez e parece sempre esclarecer.


Este é um salva-vidas @ sthames42! Eu tenho procurado por horas tentando descobrir exatamente como fazer isso. Claro, abrangente, geralmente incrível. #points Perguntas: (a) Por que o Bower está no pós-instalação quando já está na lista de pacotes? (b) Como NÃO vincular localmente os pacotes globais? Apenas não inclua "links" no comando?
MaxRocket 29/01

@MaxRocket: Ainda bem que pude ajudar. Atualizei a resposta para incluir o meu mais recente, que funciona muito melhor. Respostas: (a) o comando 'bower install' é executado após a instalação do 'npm' para instalar os componentes do Bower listados no arquivo bower.json não mostrado aqui. Queria que meu pessoal pudesse digitar 'npm install' e ter seu ambiente totalmente configurado sem precisar digitar outro comando. (b) sim
precisa saber é o seguinte

A versão atual deste script agora é mantida aqui .
sthames42

6

Você pode usar um arquivo separado, como npm_globals.txt, em vez de package.json. Esse arquivo conteria cada módulo em uma nova linha como esta,

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

Em seguida, na linha de comando, execute

< npm_globals.txt xargs npm install -g

Verifique se eles foram instalados corretamente com,

npm list -g --depth=0

Quanto a saber se você deve fazer isso ou não, eu acho que tudo depende do caso de uso. Para a maioria dos projetos, isso não é necessário; e ter o seu projeto package.jsonencapsular essas ferramentas e dependências é muito preferido.

Atualmente, porém, acho que estou sempre instalando create-react-appe outras CLIs globalmente quando pulo em uma nova máquina. É bom ter uma maneira fácil de instalar uma ferramenta global e suas dependências quando o controle de versão não importa muito.

E hoje em dia, eu estou usando npx, um corredor pacote npm , em vez de instalar pacotes globalmente.


3

Todos os módulos do package.json estão instalados em ./node_modules/

Não foi possível encontrar isso explicitamente, mas esta é a referência package.json para o NPM .


1

Crie seu próprio script para instalar dependências globais. Não é preciso muito. O package.json é bastante expansível.

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

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

Usando o exposto acima, você pode torná-lo inline, abaixo!

Veja a pré-instalação abaixo:

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

Os autores do nó podem não admitir package.json é um arquivo de projeto. Mas isso é.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.