node.js - mac - Instalar dependencias de forma global y local utilizando package.json
npm tutorial (5)
Usando npm podemos instalar los módulos globalmente usando la opción -g
. ¿Cómo podemos hacer esto en el archivo package.json?
Supongamos que estas son mis dependencias en el archivo package.json
"dependencies": {
"mongoose": "1.4.0",
"node.io" : "0.3.3",
"jquery" : "1.5.1",
"jsdom" : "0.2.0",
"cron" : "0.1.2"
}
Cuando ejecuto npm install
, solo node.io
que node.io
se instale de manera global, el resto, otros deben instalarse localmente. ¿Hay una opción para esto?
Esto es un poco viejo, pero me encontré con el requisito, así que esta es la solución que se me ocurrió.
El problema:
Nuestro equipo de desarrollo mantiene muchos productos de aplicaciones web .NET que estamos migrando a AngularJS / Bootstrap. VS2010 no se presta fácilmente a los procesos de compilación personalizados y mis desarrolladores trabajan rutinariamente en múltiples versiones de nuestros productos. Nuestro VCS es Subversion (lo sé, lo sé. Estoy tratando de cambiarme a Git pero mi molesto personal de marketing es muy exigente) y una sola solución VS incluirá varios proyectos separados. Necesitaba que mi personal tuviese un método común para inicializar su entorno de desarrollo sin tener que instalar los mismos paquetes de nodo (gulp, bower, etc.) varias veces en la misma máquina.
TL; DR:
Necesita "npm install" para instalar el entorno de desarrollo global Node / Bower, así como todos los paquetes requeridos localmente para un producto .NET.
Los paquetes globales deben instalarse solo si no están ya instalados.
Los enlaces locales a paquetes globales deben crearse automáticamente.
La solución:
Ya tenemos un marco de desarrollo común compartido por todos los desarrolladores y todos los productos, así que creé un script NodeJS para instalar los paquetes globales cuando sea necesario y crear los enlaces locales. El script reside en ".... / SharedFiles" relativo a la carpeta base del producto:
/*******************************************************************************
* $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();
};
Ahora, si quiero actualizar una herramienta global para nuestros desarrolladores, actualizo el objeto "packages" y verifico el nuevo script. Mis desarrolladores lo prueban y lo ejecutan con "node npm-setup.js" o mediante "npm install" desde cualquiera de los productos en desarrollo para actualizar el entorno global. Todo esto lleva 5 minutos.
Además, para configurar el entorno para un nuevo desarrollador, primero deben instalar NodeJS y GIT para Windows, reiniciar su computadora, revisar la carpeta "Archivos Compartidos" y cualquier producto en desarrollo, y comenzar a trabajar.
El "paquete.json" para el producto .NET llama a este script antes de la instalación:
{
"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
Tenga en cuenta que la referencia del script requiere barras diagonales incluso en un entorno Windows.
"npm ls" dará mensajes "npm ERR! extraneous:" para todos los paquetes vinculados localmente porque no están listados en las "dependencias" de package.json ".
Editar 29/01/16
La npm-setup.js
comandos actualizada npm-setup.js
anterior se ha modificado de la siguiente manera:
El paquete "versión" en
var packages
ahora es el valor "paquete" pasado a lanpm install
en la línea de comando. Esto se cambió para permitir la instalación de paquetes desde un lugar diferente al repositorio registrado.Si el paquete ya está instalado pero no es el solicitado, se elimina el paquete existente y se instala el correcto.
Por razones desconocidas, npm arrojará periódicamente un error EBUSY (-4082) al realizar una instalación o un enlace. Este error queda atrapado y el comando se vuelve a ejecutar. El error rara vez ocurre por segunda vez y parece que siempre se soluciona.
Puede usar un archivo separado, como npm_globals.txt
, en lugar de package.json
. Este archivo contendría cada módulo en una nueva línea como esta,
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
Luego en la línea de comando ejecutar,
< npm_globals.txt xargs npm install -g
Verifique que se hayan instalado correctamente con,
npm list -g --depth=0
En cuanto a si deberías hacer esto o no, creo que todo depende del caso de uso. Para la mayoría de los proyectos, esto no es necesario; y tener el package.json
su proyecto. package.json
encapsular estas herramientas y dependencias juntos es muy preferido.
Pero hoy en día encuentro que siempre estoy instalando create-react-app
y otras CLI globalmente cuando me meto en una nueva máquina. Es agradable tener una manera fácil de instalar una herramienta global y sus dependencias cuando el control de versiones no importa demasiado.
Y hoy en día, estoy usando npx
, un corredor de paquetes npm , en lugar de instalar paquetes globalmente.
Todos los módulos de package.json están instalados en ./node_modules/
No pude encontrarlo explícitamente, pero esta es la referencia de package.json para NPM .
Debido a las desventajas que se describen a continuación, recomendaría seguir la respuesta aceptada:
Use
npm install --save-dev [package_name]
luego ejecute los scripts con:
$ npm run lint $ npm run build $ npm test
Mi respuesta original pero no recomendada sigue.
En lugar de utilizar una instalación global, puede agregar el paquete a sus devDependencies
( --save-dev
) y luego ejecutar el binario desde cualquier lugar dentro de su proyecto:
"$(npm bin)/<executable_name>" <arguments>...
En tu caso:
"$(npm bin)"/node.io --help
Este ingeniero proporcionó un alias npm-exec
como acceso directo. Este ingeniero usa un shellscript llamado env.sh
Pero prefiero usar $(npm bin)
directamente, para evitar cualquier archivo adicional o configuración.
Aunque hace que cada llamada sea un poco más grande, debería funcionar , evitando:
- posibles conflictos de dependencia con paquetes globales (@nalply)
- la necesidad de
sudo
- la necesidad de configurar un prefijo npm (aunque recomiendo usar uno de todos modos)
Desventajas:
-
$(npm bin)
no funcionará en Windows. - Las herramientas más profundas en su árbol de desarrollo no aparecerán en la carpeta
npm bin
. (Instale npm-run o npm-which para encontrarlos).
Parece que una mejor solución es colocar tareas comunes (como construir y minificar) en la sección "scripts" de su package.json
. package.json
, como demuestra Jason anteriormente.
Nueva nota: probablemente no quiera o necesite hacer esto. Lo que probablemente desee hacer es colocar esos tipos de dependencias de comandos para compilación / prueba, etc. en la sección devDependencies
de su paquete.json. Cada vez que use algo de los scripts
en package.json, sus comandos devDependencies (en node_modules / .bin) actuarán como si estuvieran en su ruta.
Por ejemplo:
npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally
Luego en package.json:
// devDependencies has mocha and babel now
"scripts": {
"test": "mocha",
"build": "babel -d lib src",
"prepublish": "babel -d lib src"
}
Luego, en el símbolo del sistema, puede ejecutar:
npm run build # finds babel
npm test # finds mocha
npm publish # will run babel first
Pero si realmente desea instalarlo globalmente, puede agregar una preinstalación en la sección de scripts del paquete.json:
"scripts": {
"preinstall": "npm i -g themodule"
}
Así que en realidad mi instalación de npm ejecuta la instalación de npm otra vez ... lo cual es extraño, pero parece funcionar.
Nota: es posible que tenga problemas si usa la configuración más común para npm
donde las instalaciones del paquete Nodo global requieren sudo
. Una opción es cambiar tu configuración npm
así que esto no es necesario:
npm config set prefix ~/npm
, agregue $ HOME / npm / bin a $ PATH agregando export PATH=$HOME/npm/bin:$PATH
a su ~/.bashrc
.