Das ist ein bisschen alt, aber ich bin auf die Anforderung gestoßen. Hier ist die Lösung, die ich gefunden habe.
Das Problem:
Unser Entwicklungsteam verwaltet viele .NET-Webanwendungsprodukte, die wir auf AngularJS / Bootstrap migrieren. VS2010 eignet sich nicht einfach für benutzerdefinierte Build-Prozesse, und meine Entwickler arbeiten routinemäßig an mehreren Releases unserer Produkte. Unser VCS ist Subversion (ich weiß, ich weiß. Ich versuche, zu Git zu wechseln, aber meine lästigen Marketingmitarbeiter sind so anspruchsvoll) und eine einzige VS-Lösung wird mehrere separate Projekte enthalten. Ich brauchte meine Mitarbeiter, um eine gemeinsame Methode zum Initialisieren ihrer Entwicklungsumgebung zu haben, ohne dieselben Knotenpakete (gulp, bower usw.) mehrmals auf demselben Computer installieren zu müssen.
TL; DR:
Benötigen Sie "npm install", um die globale Node / Bower-Entwicklungsumgebung sowie alle lokal erforderlichen Pakete für ein .NET-Produkt zu installieren.
Globale Pakete sollten nur installiert werden, wenn sie noch nicht installiert sind.
Lokale Links zu globalen Paketen müssen automatisch erstellt werden.
Die Lösung:
Wir haben bereits ein gemeinsames Entwicklungsframework, das von allen Entwicklern und allen Produkten gemeinsam genutzt wird. Daher habe ich ein NodeJS-Skript erstellt, um die globalen Pakete bei Bedarf zu installieren und die lokalen Links zu erstellen. Das Skript befindet sich in ".... \ SharedFiles" relativ zum Produktbasisordner:
/*******************************************************************************
* $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();
};
Wenn ich nun ein globales Tool für unsere Entwickler aktualisieren möchte, aktualisiere ich das Objekt "packages" und checke das neue Skript ein. Meine Entwickler checken es aus und führen es entweder mit "node npm-setup.js" oder mit "npm install" von einem der in der Entwicklung befindlichen Produkte aus, um die globale Umgebung zu aktualisieren. Das Ganze dauert 5 Minuten.
Um die Umgebung für einen neuen Entwickler zu konfigurieren, müssen diese zunächst nur NodeJS und GIT für Windows installieren, ihren Computer neu starten, den Ordner "Freigegebene Dateien" und alle in der Entwicklung befindlichen Produkte überprüfen und mit der Arbeit beginnen.
Die Datei "package.json" für das .NET-Produkt ruft dieses Skript vor der Installation auf:
{
"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": {}
}
Anmerkungen
Beachten Sie, dass die Skriptreferenz auch in einer Windows-Umgebung Schrägstriche erfordert.
"npm ls" gibt "npm ERR! extraneous:" Nachrichten für alle lokal verknüpften Pakete aus, da sie nicht in den "package.json" "Abhängigkeiten" aufgeführt sind.
Bearbeiten 29.01.16
Das oben aktualisierte npm-setup.js
Skript wurde wie folgt geändert:
Paket "Version" in var packages
ist jetzt der Wert für "Paket", der npm install
in der Befehlszeile übergeben wird. Dies wurde geändert, um die Installation von Paketen von einem anderen Ort als dem registrierten Repository zu ermöglichen.
Wenn das Paket bereits installiert ist, aber nicht angefordert wird, wird das vorhandene Paket entfernt und das richtige installiert.
Aus unbekannten Gründen gibt npm bei der Installation oder Verknüpfung regelmäßig einen EBUSY-Fehler (-4082) aus. Dieser Fehler wird abgefangen und der Befehl erneut ausgeführt. Der Fehler tritt selten ein zweites Mal auf und scheint sich immer zu klären.
"preferGlobal": true
in package.json ein Modul festlegen.