In meinem package.json
habe ich folgende zwei Skripte:
"scripts": {
"start-watch": "nodemon run-babel index.js",
"wp-server": "webpack-dev-server",
}
Ich muss diese beiden Skripts parallel jedes Mal ausführen, wenn ich in Node.js entwickle. Als erstes dachte ich daran, ein drittes Skript hinzuzufügen:
"dev": "npm run start-watch && npm run wp-server"
... aber das wartet, bis start-watch
beendet ist, bevor wp-server
ausgeführt wird.
Wie kann ich diese parallel ausführen? Bitte beachten Sie, dass ich die output
dieser Befehle sehen muss. Wenn Ihre Lösung ein Build-Tool enthält, verwende ich lieber gulp
anstelle von grunt
, da ich es bereits in einem anderen Projekt verwende.
Verwenden Sie ein Paket namens gleichzeitig .
npm i concurrently --save-dev
Dann richten Sie Ihre npm run dev
-Aufgabe so ein:
"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""
Die Verwendung des Concurrently-Pakets funktioniert, aber Sie benötigen es nicht, um dies zu erreichen. Sie können einfach eine Pipe verwenden, wenn UNIX-basierte Maschinen gleichzeitig Aufgaben ausführen. Ich würde diese Methode gegenüber der anderen vorschlagen, weil Sie keine weiteren Abhängigkeiten hinzufügen müssen.
"dev": "npm run start-watch | npm run wp-server"
Wenn Sie eine UNIX-ähnliche Umgebung verwenden, verwenden Sie einfach &
als Trennzeichen:
"dev": "npm run start-watch & npm run wp-server"
Wenn Sie an einer plattformübergreifenden Lösung interessiert sind, können Sie das Modul npm-run-all verwenden:
"dev": "npm-run-all --parallel start-watch wp-server"
Von Windows cmd können Sie start
verwenden:
"dev": "start npm run start-watch && start npm run wp-server"
Jeder auf diese Weise gestartete Befehl beginnt in einem eigenen Fenster.
Sie sollten npm-run-all (oder concurrently
, parallelshell
) verwenden, da sie mehr Kontrolle über Start- und Beendigungsbefehle hat. Die Operatoren &
, |
sind schlechte Ideen, da Sie sie nach Abschluss aller Tests manuell stoppen müssen.
Dies ist ein Beispiel für die Prüfung des Winkelmessers durch npm:
scripts: {
"webdriver-start": "./node_modules/protractor/bin/webdriver-manager update && ./node_modules/protractor/bin/webdriver-manager start",
"protractor": "./node_modules/protractor/bin/protractor ./tests/protractor.conf.js",
"http-server": "./node_modules/http-server/bin/http-server -a localhost -p 8000",
"test": "npm-run-all -p -r webdriver-start http-server protractor"
}
-p
= Befehle parallel ausführen.
-r
= Beenden Sie alle Befehle, wenn einer von ihnen mit einem Beendigungscode von Null endet.
Wenn Sie npm run test
ausführen, wird der Selenium-Treiber gestartet, der HTTP-Server (für die Bereitstellung Ihrer Dateien) und der Winkelmesser-Test gestartet. Sobald alle Tests abgeschlossen sind, werden der http-Server und der Selenium-Treiber geschlossen.
Eine bessere Lösung ist die Verwendung von &
"dev": "npm run start-watch & npm run wp-server"
Wenn Sie das doppelte Et-Zeichen durch ein einzelnes Et-Zeichen ersetzen, werden die Skripts gleichzeitig ausgeführt.
Ich habe fast alle Lösungen von oben überprüft und nur mit npm-run-all konnte ich alle Probleme lösen. Der Hauptvorteil gegenüber allen anderen Lösungen ist die Fähigkeit, Skript mit Argumenten ausführen auszuführen.
{
"test:static-server": "cross-env NODE_ENV=test node server/testsServer.js",
"test:jest": "cross-env NODE_ENV=test jest",
"test": "run-p test:static-server \"test:jest -- {*}\" --",
"test:coverage": "npm run test -- --coverage",
"test:watch": "npm run test -- --watchAll",
}
Hinweis
run-p
ist eine Abkürzung fürnpm-run-all --paraller
.
Dadurch kann ich den Befehl mit Argumenten wie npm run test:watch -- Something
ausführen.
EDIT:
Es gibt eine weitere nützliche Option für npm-run-all
:
-r, --race - - - - - - - Set the flag to kill all tasks when a task
finished with zero. This option is valid only
with 'parallel' option.
Fügen Sie -r
zu Ihrem npm-run-all
-Skript hinzu, um alle Prozesse zu beenden, wenn der Code 0
abgeschlossen ist. Dies ist besonders nützlich, wenn Sie einen HTTP-Server und ein anderes Skript ausführen, das den Server verwendet.
"test": "run-p -r test:static-server \"test:jest -- {*}\" --",
Ich habe eine Crossplatform-Lösung ohne zusätzliche Module . Ich suchte nach etwas wie einem try catch Block, den ich sowohl in der cmd.exe als auch in der bash verwenden konnte.
Die Lösung ist command1 || command2
, die in beiden Umgebungen gleich zu funktionieren scheint. Die Lösung für das OP lautet also:
"scripts": {
"start-watch": "nodemon run-babel index.js",
"wp-server": "webpack-dev-server",
// first command is for the cmd.exe, second one is for the bash
"dev": "(start npm run start-watch && start npm run wp-server) || (npm run start-watch & npm run wp-server)",
"start": "npm run dev"
}
Dann funktioniert der einfache npm start
(und npm run dev
) auf allen Plattformen!
npm-run-all --parallel task1 task2
bearbeiten:
Sie müssen zuvor npm-run-all installiert haben. Überprüfen Sie auch diese Seite für andere Nutzungsszenarien.
In diesem Fall würde ich die beste Wette sagen Wenn dieses Skript für ein privates Modul bestimmt ist, das nur auf * nix-basierten Maschinen ausgeführt werden soll , können Sie den Steueroperator für das Aufspalten von Prozessen verwenden. Dies sieht folgendermaßen aus: &
Ein Beispiel dafür in einer partiellen package.json-Datei:
{
"name": "npm-scripts-forking-example",
"scripts": {
"bundle": "watchify -vd -p browserify-hmr index.js -o bundle.js",
"serve": "http-server -c 1 -a localhost",
"serve-bundle": "npm run bundle & npm run serve &"
}
Sie führen sie dann beide parallel über npm run serve-bundle
aus. Sie können die Skripte so erweitern, dass die PIDs des gegabelten Prozesses in einer Datei ausgegeben werden:
"serve-bundle": "npm run bundle & echo \"$!\" > build/bundle.pid && npm run serve & echo \"$!\" > build/serve.pid && npm run open-browser",
Google etwas wie bash control operator für forking, um mehr über seine Funktionsweise zu erfahren. Ich habe auch einige weitere Informationen zur Verwendung von Unix-Techniken in folgenden Knotenprojekten bereitgestellt:
Wenn Sie nicht unter Windows arbeiten, funktionieren Unix-Tools/-Techniken oft gut, um mit Knotenscripts etwas zu erreichen, weil:
Module für Systemaufgaben in Nodeland sind häufig auch Abstraktionen oder Annäherungen an Unix-Tools, von fs
bis streams
.
Sie können einen &
für ein parallel ausgeführtes Skript verwenden
"dev": "npm run start-watch & npm run wp-server"
Eine weitere Option zum Ausführen mehrerer Knotenscripts ist ein einzelnes Knotenskript, das fork viele andere ausführen kann. Gabelung wird in Node nativ unterstützt, fügt also keine Abhängigkeiten hinzu und ist plattformübergreifend.
Dadurch würden die Skripts nur so wie sie sind ausgeführt und davon ausgegangen, dass sie sich im Verzeichnis des übergeordneten Skripts befinden.
// fork-minimal.js - run with: node fork-minimal.js
const childProcess = require('child_process');
let scripts = ['some-script.js', 'some-other-script.js'];
scripts.forEach(script => childProcess.fork(script));
Dadurch würden die Skripts mit Argumenten ausgeführt und durch die vielen verfügbaren Optionen konfiguriert.
// fork-verbose.js - run with: node fork-verbose.js
const childProcess = require('child_process');
let scripts = [
{
path: 'some-script.js',
args: ['-some_arg', '/some_other_arg'],
options: {cwd: './', env: {NODE_ENV: 'development'}}
},
{
path: 'some-other-script.js',
args: ['-another_arg', '/yet_other_arg'],
options: {cwd: '/some/where/else', env: {NODE_ENV: 'development'}}
}
];
let processes = [];
scripts.forEach(script => {
let runningScript = childProcess.fork(script.path, script.args, script.options);
// Optionally attach event listeners to the script
runningScript.on('close', () => console.log('Time to die...'))
runningScripts.Push(runningScript); // Keep a reference to the script for later use
});
Das Forking bietet außerdem den zusätzlichen Vorteil, dass das übergeordnete Skript sowohl Ereignisse aus den untergeordneten untergeordneten Prozessen empfangen als auch zurücksenden kann. Ein allgemeines Beispiel ist, dass das übergeordnete Skript seine verzweigten Kinder abtötet.
runningScripts.forEach(runningScript => runningScript.kill());
Weitere verfügbare Ereignisse und Methoden finden Sie in der ChildProcess
-Dokumentation
Ich bin auf Probleme mit &
und |
gestoßen, die jeweils den Status und die Fehlerausgabe beenden.
Andere Lösungen möchten jede Aufgabe mit einem bestimmten Namen ausführen, wie beispielsweise npm-run-all, was nicht mein Anwendungsfall war.
Also habe ich npm-run-parallel erstellt, das npm-Skripts asynchron ausführt und zurückmeldet, wenn sie fertig sind.
Für Ihre Skripte wäre es also:
npm-run-parallel wp-server start-watch
Ich benutze npm-run-all schon seit einiger Zeit, bin aber nie damit klar gekommen, weil die Ausgabe des Befehls im Watch-Modus nicht gut zusammenarbeitet. Wenn ich beispielsweise create-react-app
und jest
im Überwachungsmodus starte, kann ich nur die Ausgabe des letzten Befehls sehen, den ich ausgeführt habe. Also habe ich die meiste Zeit alle meine Befehle manuell ausgeführt ...
Deshalb implementiere ich meine eigene lib, run-screen . Es ist noch ein sehr junges Projekt (von gestern: p), aber es könnte schlimmer sein, es anzuschauen, in deinem Fall wäre es:
run-screen "npm run start-watch" "npm run wp-server"
Drücken Sie dann die Zifferntaste 1
, um die Ausgabe von wp-server
anzuzeigen, und drücken Sie 0
, um die Ausgabe von start-watch
anzuzeigen.
In meinem Fall habe ich zwei Projekte, eines warUIund das andere warAPI, und beide haben ein eigenes Skript in ihren jeweiligen package.json
-Dateien.
Also, hier ist was ich getan habe.
npm run --prefix react start& npm run --prefix express start&
Einfaches Knotenskript, mit dem Sie ohne großen Aufwand loslegen können. Verwenden Sie readline, um Ausgaben zu kombinieren, damit die Zeilen nicht verstümmelt werden.
const { spawn } = require('child_process');
const readline = require('readline');
[
spawn('npm', ['run', 'start-watch']),
spawn('npm', ['run', 'wp-server'])
].forEach(child => {
readline.createInterface({
input: child.stdout
}).on('line', console.log);
readline.createInterface({
input: child.stderr,
}).on('line', console.log);
});