Wie kann ich mehrere npm-Skripte gleichzeitig ausführen?


542

In meinem habe package.jsonich diese beiden Skripte:

  "scripts": {
    "start-watch": "nodemon run-babel index.js",
    "wp-server": "webpack-dev-server",
  }

Ich muss diese beiden Skripte jedes Mal parallel ausführen, wenn ich mit der Entwicklung in Node.js beginne. Das erste, woran ich dachte, war das Hinzufügen eines dritten Skripts wie dieses:

"dev": "npm run start-watch && npm run wp-server"

... aber das wird warten, start-watchbis es fertig ist, bevor es läuft wp-server.

Wie kann ich diese parallel ausführen? Bitte denken Sie daran, dass ich die outputdieser Befehle sehen muss. Wenn Ihre Lösung ein Build-Tool enthält, würde ich es lieber verwenden, gulpanstatt gruntes bereits in einem anderen Projekt zu verwenden.


23
&&führt Ihre Skripte nacheinander aus, während &sie parallel ausgeführt werden .
vsync

Ein schneller Weg ist es npm run start-watch & npm run wp-server. Dadurch wird der erste Befehl als Hintergrundthread ausgeführt. Dies funktioniert sehr gut, wenn einer der Befehle nicht lange ausgeführt wird und später nicht manuell beendet werden muss. So etwas concurrentlykönnen Sie alle Fäden in der gleichen Zeit mit STRG + C töten.
Joshua Pinter

Antworten:


616

Verwenden Sie ein Paket, das gleichzeitig aufgerufen wird .

npm i concurrently --save-dev

Richten Sie dann Ihre npm run devAufgabe folgendermaßen ein:

"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""

11
node ./node_modules/concurrently/src/main.jswird nicht gebraucht. concurrentganz gut in Skripten arbeiten , da das Modul einen Behälter zu installieren./node_modules/.bin/concurrent
Raine

14
Es gibt auch Parallelen . Ich empfehle tatsächlich, dass einer concurrentlymehrere Streams verwendet, die die Konsolenausgabe beeinträchtigen (Farben können seltsam werden, Cursor weg), während dieses Problemparallelshell nicht auftritt .
Stijn de Witt

3
Die von @StijndeWitt gleichzeitig erwähnten Fehler wurden jetzt in Version 2.0.0 behoben . Sie können den --rawModus verwenden, um Farben in der Ausgabe beizubehalten.
Kimmo

23
@StijndeWitt Parallelshell wurde zugunsten von npm-run-all github.com/keithamus/…
jtzero

12
Es muss eine bessere Möglichkeit für uns geben, Javascript-Build / Run-Skripte zu verwalten. Alles für diese Plattform scheint zusammengeheftet. Anführungszeichen mit maskierten Anführungszeichen und npm-Builds, um andere 'npm run'-Builds aufzurufen. Dies wird ziemlich schmerzhaft.
Andrew T Finnell

141

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"

14
Ich mache das - von Zeit zu Zeit, wenn ich "Strg-C" npm drücke, bleibt der Befehl im Hintergrund hängen ... Irgendwelche Ideen?
Kamil Tomšík

13
a && bstartet bnach aerfolgreichem Abschluss, aber nodemon stoppt nie ohne Fehler, so dass das nicht funktionieren kann. a & bstartet a, verschiebt es in den Hintergrund und startet bsofort. Sieg! a | bleitet die stdout von azu der stdin, für bdie beide gleichzeitig laufen müssen. Obwohl dies den gewünschten Effekt zu haben scheint, sollten Sie es hier nicht verwenden.
j2L4e

8
@ KamilTomšík &ist eine wirklich schlechte Idee, da sie den Prozess löst. Dies bedeutet, dass dies npmnicht mehr der übergeordnete Prozess ist. Sie werden mit einem Zombie enden, mit npm run start-watchdem Sie nicht getötet werden ctrl-c.
Ngryman

6
Fügen Sie einfach hinzu wait, um das Problem mit hängenden Prozessen zu mildern:"dev": "npm run start-watch & npm run wp-server & wait"
Ruslan Prokopchuk

2
Es ist kein Zombie. Unter &Unix verhindert der Befehl jedoch, dass er auf Cc / Cz reagiert, und verhindert auch, dass sich sein Rückkehrcode im Falle eines Fehlers ausbreitet.
Binki

77

Unter Windows Cmd können Sie Folgendes verwenden start:

"dev": "start npm run start-watch && start npm run wp-server"

Jeder auf diese Weise gestartete Befehl startet in einem eigenen Fenster.


2
Perfekte Lösung! Ich liebe es, dass es das neue Fenster öffnet. Groß für VS2015 package.json Bedürfnisse
TetraDev

13
Dies funktioniert nicht, wenn Sie Überwachungsaufgaben haben, da &&vor dem Starten des zweiten Befehls auf den Abschluss des ersten Befehls gewartet wird und eine Überwachungsaufgabe niemals beendet wird.
Benny Neugebauer

2
@BennyNeugebauer Vor den Befehlen steht der Befehl "start", der für jeden Befehl eine neue Befehlszeile öffnet. Anfangs war ich auch verwirrt, weil ich dachte, "die Verwendung des Operators && wird nicht funktionieren". Diese Lösung ist sehr einfach und erfordert keine zusätzlichen Pakete / Arbeiten vom Entwickler.
Addison

5
Das ist falsch. Der Befehl wird nacheinander ausgeführt. Unter Windows müssen Sie ein Plugin verwenden, um Befehle gleichzeitig ausführen zu können.
Zhekaus

1
Ist das nicht Windows-spezifisch?
Binki

62

Sie sollten npm-run-all (oder concurrently, parallelshell) verwenden, da es mehr Kontrolle über das Starten und Beenden von Befehlen hat. Die Betreiber &, |sind schlechte Ideen , weil Sie manuell brauchen, um es zu stoppen , nachdem alle Tests abgeschlossen sind.

Dies ist ein Beispiel für Winkelmessertests bis 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 = Töte alle Befehle, wenn einer von ihnen mit einem Exit-Code von Null endet.

Durch Ausführen npm run testwird der Selenium-Treiber gestartet, der http-Server gestartet (um Ihnen Dateien bereitzustellen) und Winkelmessertests ausgeführt. Sobald alle Tests abgeschlossen sind, werden der http-Server und der Selentreiber geschlossen.


3
Ich frage mich jedoch, wie dies für die Ausführung der Tests richtig funktioniert. Während Webdriver-Start und http-Server parallel ausgeführt werden können, sollte die Winkelmesser-Task erst nach den ersten beiden ausgeführt werden.
Asenovm

@asenovm für auftragsabhängige Aufgaben, warum nicht einfach gulpund verwenden gulp-sync?
r3wt

30

Sie können eines &für parallel ausgeführtes Skript verwenden

"dev": "npm run start-watch & npm run wp-server"

Referenzlink


Funktioniert das auch unter Windows? Entschuldigung, ich bin ziemlich neu in Node und weiß nicht, wie ich das überprüfen soll!
Benison Sam

@BenisonSam nein, funktioniert aber auf Mac
Shanehoban

25

Eine bessere Lösung ist zu verwenden &

"dev": "npm run start-watch & npm run wp-server"

54
Nein, es ist nicht besser, weil es nicht auf allen Plattformen funktioniert.
Stijn de Witt

Ich wusste das nicht. Auf welchen Plattformen funktioniert es nicht? @Corey - aktualisieren Sie Ihre Antwort mit der Warnung auf Inter-Op und ich werde Sie upvoten
Ashley Coolman

8
&funktioniert unter Windows, aber es funktioniert anders. Unter OSX werden beide Befehle gleichzeitig ausgeführt, unter Windows wird jedoch der erste Befehl ausgeführt, und nachdem der erste Befehl vorhanden ist, wird der zweite Befehl ausgeführt.
Trevor

3
Nein, es ist nicht so, dass es den Prozess löst, Sie werden es nicht auf einfache Weise beenden können.
Ngryman

2
@ngryman Das habe ich auch erwartet. Ich habe dies jedoch versucht und es beendet alle drei Prozesse (dev, start-watch und wp-server), wenn Sie Strg + C drücken.
musicin3d

17

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 Möglichkeit, Skripte mit Argumenten 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-pist Abkürzung fürnpm-run-all --parallel

Dadurch kann ich einen Befehl mit Argumenten wie ausführen npm run test:watch -- Something.

BEARBEITEN:

Es gibt noch eine 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 -rIhrem npm-run-allSkript hinzu, um alle Prozesse zu beenden, wenn Sie mit Code fertig sind 0. 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 -- {*}\" --",

15

Ich habe eine plattformübergreifende Lösung ohne zusätzliche Module . Ich suchte nach so etwas wie einem Try-Catch-Block, den ich sowohl in der cmd.exe als auch in der Bash verwenden konnte.

Die Lösung command1 || command2scheint in beiden Umgebungen gleich zu funktionieren. 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 einfach npm start(und npm run dev) auf allen Plattformen!


11

Wenn Sie das doppelte kaufmännische Und durch ein einzelnes kaufmännisches Und ersetzen, werden die Skripts gleichzeitig ausgeführt.


Genau, es ist einfach und elegant, ohne Abhängigkeiten oder andere Magie.
MagikMaker

1
@ Ginzburg Weil nicht für alle Plattformen gleich funktioniert, wie Sie in anderen Antworten sehen können.
Jorge Fuentes González

6

Schnelle Lösung

In diesem Fall würde ich die beste Wahl sagen. Wenn dieses Skript für ein privates Modul vorgesehen ist, das nur auf * nix-basierten Computern ausgeführt werden soll , können Sie den Steuerungsoperator zum Verzweigen von Prozessen verwenden. Dies sieht folgendermaßen aus:&

Ein Beispiel hierfü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 würden dann beide parallel über ausführen npm run serve-bundle . Sie können die Skripte erweitern, um die Pids des gegabelten Prozesses in eine Datei wie folgt auszugeben:

"serve-bundle": "npm run bundle & echo \"$!\" > build/bundle.pid && npm run serve & echo \"$!\" > build/serve.pid && npm run open-browser",

Google so etwas wie Bash Control Operator zum Gabeln , um mehr darüber zu erfahren, wie es funktioniert. Im Folgenden habe ich einige weitere Informationen zur Nutzung von Unix-Techniken in Node-Projekten bereitgestellt:

Weiterer Kontext RE: Unix Tools & Node.js.

Wenn Sie nicht unter Windows arbeiten, funktionieren Unix-Tools / -Techniken häufig gut, um mit Node-Skripten etwas zu erreichen, weil:

  1. Ein Großteil von Node.js ahmt liebevoll Unix-Prinzipien nach
  2. Sie sind auf * nix (inkl. OS X) und NPM verwendet sowieso eine Shell

Module für Systemaufgaben in Nodeland sind häufig auch Abstraktionen oder Annäherungen von Unix-Tools von fsbis streams.


1
Nein, da der &Operator unter Windows nicht unterstützt wird.
Stijn de Witt

3
@StijndeWitt mein Beitrag sagt "Wenn Sie nicht unter Windows sind ...". 0% der Leute, mit denen ich bei einem der größten Technologieunternehmen der Welt zusammenarbeite, betreiben Node unter Windows. Mein Beitrag ist also für viele Entwickler immer noch wertvoll.
James_womack

2
Es ist eine Art Zirkelschluss, nicht wahr? Wenn Sie Ihre npm Skripte so schreiben Sie nicht der Lage sein, Windows - verwenden , weil es wird nicht funktionieren. Also benutzt niemand Windows, also spielt es keine Rolle, dass es nicht funktioniert ... Sie erhalten plattformabhängige Software. Wenn es nun sehr schwierig ist, plattformübergreifend zu arbeiten, ist dies möglicherweise ein guter Kompromiss. Aber dieses Problem hier ist sehr einfach mit Standard-npm-Skripten wie gleichzeitig und parallel zu lösen .
Stijn de Witt

2
@StijndeWitt Keine meiner Überlegungen war zirkulär. Ich habe eine Tatsachenerklärung ohne Argumentation abgegeben. Wir veröffentlichen Techniken, die Node-Entwicklern gemeinsam sind, von denen viele auf Linux-Servern erstellt und bereitgestellt werden. Ja, es sollte unter Windows funktionieren, wenn es sich um ein Userland-Skript handelt, aber die meisten npm-Skripte sind für die Entwicklung und Bereitstellung vorgesehen - hauptsächlich auf * nix-Computern. In Bezug auf die Module, die Sie erwähnt haben, a) ist es eine enorme Herausforderung, gleichzeitig und parallel "Standard" zu nennen (~ 1500 Downloads pro Tag sind in NPMland weit vom Standard entfernt) und b) wenn Sie zusätzliche Software für einen parallelen Prozess benötigen, können Sie diese auch verwenden Schluck.
James_womack

@StijndeWitt Ich schätze es, auf diese Module aufmerksam gemacht zu werden - danke
james_womack


5

Wie wäre es mit Gabeln

Eine weitere Möglichkeit , mehr Knoten Skripte auszuführen ist mit einem einzelnen Node - Skript, das kann gabelt viele andere. Forking wird in Node nativ unterstützt, fügt also keine Abhängigkeiten hinzu und ist plattformübergreifend.


Minimales Beispiel

Dies würde die Skripte einfach so ausführen, wie sie sind, und davon ausgehen, 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));

Ausführliches Beispiel

Dies würde die Skripte mit Argumenten ausführen 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
});

Kommunikation mit gegabelten Skripten

Forking hat außerdem den zusätzlichen Vorteil, dass das übergeordnete Skript Ereignisse von den gegabelten untergeordneten Prozessen empfangen und zurücksenden kann. Ein häufiges Beispiel ist, dass das übergeordnete Skript seine gegabelten Kinder tötet.

 runningScripts.forEach(runningScript => runningScript.kill());

Weitere verfügbare Ereignisse und Methoden finden Sie in der ChildProcessDokumentation


3

Ich hatte Probleme mit &und |, die den Status beenden und Fehler auslösen.

Andere Lösungen möchten jede Aufgabe mit einem bestimmten Namen ausführen, z. B. npm-run-all, was nicht mein Anwendungsfall war.

Also habe ich npm-run-parallel erstellt , das npm-Skripte 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


2

In meinem Fall habe ich zwei Projekte, eines war UI und das andere war API , und beide haben ein eigenes Skript in ihren jeweiligen package.jsonDateien.

Also, hier ist was ich getan habe.

npm run --prefix react start&  npm run --prefix express start&

Wie Ihre Lösung. Haben Sie auch UI ( node app) und API (Angular in einem Unterordner src , Vermutung ist cd src/ng serve), funktioniert nur der erste Teil. Zum Beispiel node app& cd src& ng serve.
Jeb50


1

Ich benutze npm-run-all seit einiger Zeit, bin aber nie damit klar gekommen, weil die Ausgabe des Befehls im Überwachungsmodus nicht gut zusammenarbeitet. Zum Beispiel, wenn ich anfange create-react-appundjest im Überwachungsmodus befinde, kann ich nur die Ausgabe des zuletzt ausgeführten Befehls sehen. Die meiste Zeit habe ich alle meine Befehle manuell ausgeführt ...

Aus diesem Grund implementiere ich meine eigene lib, run-screen . Es ist noch ein sehr junges Projekt (von gestern: p), aber es könnte sich lohnen, es sich anzusehen, in Ihrem Fall wäre es:

run-screen "npm run start-watch" "npm run wp-server"

Dann drücken Sie die Zifferntaste 1, um die Ausgabe von wp-serveranzuzeigen 0, und drücken , um die Ausgabe von anzuzeigen start-watch.


1

Meine Lösung ähnelt der von Piittis, obwohl ich einige Probleme mit Windows hatte. Also musste ich mich für win32 validieren.

const { spawn } = require("child_process");

function logData(data) {
    console.info(`stdout: ${data}`);
}

function runProcess(target) {
    let command = "npm";
    if (process.platform === "win32") {
        command = "npm.cmd"; // I shit you not
    }
    const myProcess = spawn(command, ["run", target]); // npm run server

    myProcess.stdout.on("data", logData);
    myProcess.stderr.on("data", logData);
}

(() => {
    runProcess("server"); // package json script
    runProcess("client");
})();

0

Einfaches Knotenskript, mit dem Sie ohne großen Aufwand loslegen können. Verwenden Sie readline, um Ausgaben zu kombinieren, damit die Zeilen nicht beschädigt 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);
});

0
"dev": "(cd api && start npm run start) & (cd ../client && start npm run start)"

diese Arbeit in Windows

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.