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:
È necessario "npm install" per installare l'ambiente di sviluppo globale Node / Bower e tutti i pacchetti richiesti localmente per un prodotto .NET.
I pacchetti globali dovrebbero essere installati solo se non sono già installati.
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.js
script aggiornato sopra è stato modificato come segue:
Il pacchetto "versione" in var packages
è ora il valore "pacchetto" passato alla npm install
riga 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.
"preferGlobal": true
dentro package.json per un modulo.