Come posso eseguire più script npm in parallelo?


543

Nel mio package.jsonho questi due script:

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

Devo eseguire questi 2 script in parallelo ogni volta che inizio a sviluppare in Node.js. La prima cosa che ho pensato è stata l'aggiunta di un terzo script come questo:

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

... ma aspetterà start-watchdi finire prima di correre wp-server.

Come posso eseguirli in parallelo? Tieni presente che ho bisogno di vedere outputquesti comandi. Inoltre, se la tua soluzione prevede uno strumento di creazione, preferirei utilizzare gulpinvece che gruntperché già lo uso in un altro progetto.


23
&&eseguirà i tuoi script in sequenza mentre &li eseguirà in parallelo .
vsync,

Un modo rapido per farlo è npm run start-watch & npm run wp-server. Questo eseguirà il primo comando come thread in background. Funziona davvero bene quando uno dei comandi non è in esecuzione a lungo e non è necessario uscire manualmente in seguito. Qualcosa del genere concurrentlyti consente di uccidere tutti i thread contemporaneamente con CTRL-C.
Joshua Pinter

Risposte:


617

Utilizzare un pacchetto chiamato contemporaneamente .

npm i concurrently --save-dev

Quindi imposta l' npm run devattività in questo modo:

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

11
node ./node_modules/concurrently/src/main.jsnon è necessario. concurrentfunzionerà perfettamente negli script perché il modulo installa un cestino per./node_modules/.bin/concurrent
raine l'

14
C'è anche parallelshell . In realtà raccomando che uno concurrentlyutilizzi più flussi che pasticciano con l'output della console (i colori possono diventare strani, il cursore è scomparso) mentre parallelshellnon ha questo problema .
Stijn de Witt,

3
I bug menzionati contemporaneamente da @StijndeWitt sono stati corretti nella versione 2.0.0 . È possibile utilizzare la --rawmodalità per preservare i colori nell'output.
Kimmo,

23
@StijndeWitt parallelshell è stato deprecato a favore di npm-run-all github.com/keithamus/…
jtzero,

12
Ci deve essere un modo migliore per gestire gli script di build / run di Javascript. Tutto per questa piattaforma sembra combinato. virgolette con virgolette sfuggite e build npm per chiamare altre build 'npm run'. Questo sta diventando piuttosto doloroso.
Andrew T Finnell,

142

Se stai usando un ambiente simile a UNIX, usa solo &come separatore:

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

Altrimenti, se sei interessato a una soluzione multipiattaforma, puoi utilizzare il modulo npm-run-all :

"dev": "npm-run-all --parallel start-watch wp-server"

14
Faccio questo - di tanto in tanto quando "ctrl-c" npm, il comando continua a rimanere in background ... Qualche idea?
Kamil Tomšík,

13
a && binizia bdopo aver aterminato correttamente, ma nodemon non si ferma mai senza errori, quindi non può funzionare. a & binizia a, lo sposta sullo sfondo e inizia bsubito. Vincere! a | bconvoglia lo stdout aallo stdin di bcui richiede entrambi l'esecuzione simultanea. Anche se questo potrebbe sembrare l'effetto desiderato, non dovresti usarlo qui.
j2L4e,

8
@ KamilTomšík &è una pessima idea in quanto distacca il processo. Significa che npmnon sarà più il processo genitore. Ti ritroverai con uno zombi con npm run start-watchcui non sarai ucciso ctrl-c.
ngryman,

6
Basta aggiungere waitper mitigare il problema con i processi sospesi:"dev": "npm run start-watch & npm run wp-server & wait"
Ruslan Prokopchuk

2
Non è uno zombi. Ma &su unix impedisce al comando di rispondere a Cc / Cz e impedisce anche la propagazione del suo codice di ritorno in caso di errore.
binki,

77

Da Windows cmd è possibile utilizzare start:

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

Ogni comando lanciato in questo modo inizia nella sua finestra.


2
Soluzione perfetta! Adoro il fatto che avvii la nuova finestra. Grande per il pacchetto VS2015.Json ha bisogno
TetraDev

13
Questo non funziona se hai compiti di controllo perché &&attende che il primo comando finisca prima di iniziare il secondo comando e un compito di controllo non finirà mai.
Benny Neugebauer,

2
@BennyNeugebauer I comandi sono preceduti dal comando "start" che apre una nuova riga di comando per ciascuno dei comandi. All'inizio ero confuso anche perché pensavo che "l'uso dell'operatore && non funzionerà". Questa soluzione è molto semplice e non richiede pacchetti / lavori aggiuntivi da parte dello sviluppatore.
Addison,

5
Questo è sbagliato. Il comando verrà eseguito in sequenza. Su Windows devi usare un plugin per eseguire comandi contemporaneamente.
Zhekaus,

1
Questo non è specifico di Windows?
binki,

62

Dovresti usare npm-run-all (o concurrently, parallelshell), perché ha un maggiore controllo sull'avvio e l'uccisione dei comandi. Gli operatori &,| sono cattive idee, perché avrete bisogno di fermare manualmente dopo tutti i test sono finiti.

Questo è un esempio per il test del goniometro tramite 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 = Esegui comandi in parallelo.

-r = Uccidi tutti i comandi quando uno di essi termina con un codice di uscita pari a zero.

L'esecuzione npm run testavvierà il driver Selenium, avvierà il server http (per servire i tuoi file) ed eseguirà i test del goniometro. Una volta terminati tutti i test, chiuderà il server http e il driver selenio.


3
Tuttavia, mi chiedo come funzioni correttamente per l'esecuzione dei test. Mentre webdriver-start e http-server possono essere eseguiti in parallelo, l'attività del goniometro dovrebbe essere eseguita solo dopo i primi due.
asenovm,

@asenovm per le attività dipendenti dall'ordine, perché non usare gulpe gulp-sync?
r3wt


25

Una soluzione migliore è usare &

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

54
No, non è meglio perché non funziona su tutte le piattaforme.
Stijn de Witt,

Non lo sapevo. Su quali piattaforme non funziona? @Corey - aggiorna la tua risposta con l'avvertimento su inter-op e ti voterò
Ashley Coolman

8
&funziona su Windows, ma funziona in modo diverso. Su OSX, eseguirà entrambi i comandi contemporaneamente, ma su Windows eseguirà il primo comando e dopo che esiste il primo comando, eseguirà il secondo comando.
Trevor,

3
No, non è come stacca il processo, non sarai in grado di ucciderlo in modo semplice.
ngryman,

2
@ngryman È quello che mi aspettavo anche io. Tuttavia, ho provato questo e uccide tutti e tre i processi (dev, start-watch e wp-server) quando premi Ctrl + C.
musicin3d

17

Ho controllato quasi tutte le soluzioni dall'alto e solo con npm-run-all sono stato in grado di risolvere tutti i problemi. Il vantaggio principale rispetto a tutte le altre soluzioni è la possibilità di eseguire script con argomenti .

{
  "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",
}

Nota run-pè scorciatoia pernpm-run-all --parallel

Questo mi permette di eseguire il comando con argomenti come npm run test:watch -- Something.

MODIFICARE:

C'è un'altra opzione utile per 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.

Aggiungi -ral tuo npm-run-allscript per terminare tutti i processi quando uno ha terminato con il codice 0. Ciò è particolarmente utile quando si esegue un server HTTP e un altro script che utilizzano il server.

  "test": "run-p -r test:static-server \"test:jest -- {*}\" --",

15

Ho una soluzione multipiattaforma senza moduli aggiuntivi . Stavo cercando qualcosa come un blocco catch try che potevo usare sia nel cmd.exe che nel bash.

La soluzione è command1 || command2che sembra funzionare in entrambi gli ambienti stessi. Quindi la soluzione per l'OP è:

"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"
}

Quindi semplice npm start(e npm run dev) funzionerà su tutte le piattaforme!


11

Se si sostituisce la doppia e commerciale con una singola e commerciale, gli script verranno eseguiti contemporaneamente.


Esatto, è semplice ed elegante, non c'è bisogno di dipendenze o altra magia.
magikMaker

1
@Ginzburg Perché non funziona allo stesso modo per tutte le piattaforme, come puoi vedere in altre risposte.
Jorge Fuentes González,

6

Soluzione rapida

In questo caso, direi la scommessa migliore se questo script è per un modulo privato destinato a funzionare solo su macchine basate su * nix , puoi usare l'operatore di controllo per i processi di fork, che assomiglia a questo:&

Un esempio di ciò in un file package.json parziale:

{
  "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 &"
  }

Li eseguiresti entrambi in parallelo tramite npm run serve-bundle. È possibile migliorare gli script per generare i pid del processo biforcato in un file in questo modo:

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

Google qualcosa come l' operatore di controllo bash per il fork per saperne di più su come funziona. Ho anche fornito un ulteriore contesto per sfruttare le tecniche Unix nei progetti Node di seguito:

Ulteriore contesto RE: Unix Tools & Node.js

Se non sei su Windows, gli strumenti / le tecniche Unix spesso funzionano bene per ottenere qualcosa con gli script Node perché:

  1. Gran parte di Node.js imita amorevolmente i principi di Unix
  2. Sei su * nix (incl. OS X) e NPM usa comunque una shell

I moduli per le attività di sistema in Nodeland sono spesso anche astrazioni o approssimazioni di strumenti Unix, da fsa streams.


1
No, poiché l' &operatore non è supportato su Windows.
Stijn de Witt,

3
@StijndeWitt il mio post dice "Se non sei su Windows ...". Lo 0% delle persone con cui lavoro, in una delle più grandi aziende tecnologiche al mondo, esegue Node su Windows. Quindi chiaramente il mio post è ancora prezioso per molti sviluppatori.
james_womack,

2
È un po 'un modo circolare di ragionare, non è vero? Se scrivi gli script npm in questo modo non sarai in grado di usare Windows perché non funzionerà. Quindi nessuno usa Windows, quindi non importa che non funzioni ... Finisci con un software dipendente dalla piattaforma. Ora, se la cosa da fare è molto difficile da fare multipiattaforma, allora potrebbe essere un buon compromesso da fare. Ma questo problema qui è molto facile da fare con gli script npm standard come contemporaneamente e parallelshell .
Stijn de Witt,

2
@StijndeWitt Nessuno dei miei ragionamenti era circolare. Ho fatto una dichiarazione di fatto senza ragionamento. Pubblichiamo tecniche comuni agli sviluppatori di Node, molti dei quali compilano e distribuiscono su server Linux. Sì, dovrebbe funzionare su Windows se si tratta di uno script userland, ma la maggior parte degli script npm sono destinati allo sviluppo e alla distribuzione, principalmente su macchine * nix. Per quanto riguarda i moduli che hai citato a) è un enorme allungamento chiamare contemporaneamente "parallel" e parallelshell (~ 1500 download al giorno sono lontani dallo standard in NPMland) eb) se hai bisogno di software aggiuntivo per un processo parallelo, potresti anche usare Sorso.
james_womack,

@StijndeWitt Apprezzo molto la consapevolezza di quei moduli, grazie
james_womack

6
npm-run-all --parallel task1 task2

modificare:

È necessario disporre di npm-run-all installato in anticipo. Controlla anche questa pagina per altri scenari di utilizzo.


5

Che ne dici di biforcarti

Un'altra opzione per eseguire più script Node è con un singolo script Node, che può rovesciare molti altri. Forking è supportato nativamente in Node, quindi non aggiunge dipendenze ed è multipiattaforma.


Esempio minimo

Ciò eseguirà semplicemente gli script così come sono e presupponendo che si trovino nella directory dello script principale.

// 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));

Esempio dettagliato

Ciò eseguirà gli script con argomenti e configurati dalle molte opzioni disponibili.

// 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
});

Comunicare con script biforcuti

Forking ha anche l'ulteriore vantaggio che lo script padre può ricevere eventi dai processi figlio biforcati e rispedirli. Un esempio comune è che lo script padre uccida i suoi figli biforcuti.

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

Per altri eventi e metodi disponibili consultare la ChildProcessdocumentazione


3

Ho riscontrato problemi con &e |, quali stati di uscita e lancio degli errori, rispettivamente.

Altre soluzioni vogliono eseguire qualsiasi attività con un determinato nome, come npm-run-all, che non era il mio caso d'uso.

Così ho creato npm-run-parallel che esegue gli script npm in modo asincrono e riporta quando hanno finito.

Quindi, per i tuoi script, sarebbe:

npm-run-parallel wp-server start-watch


2

Nel mio caso ho due progetti, uno era UI e l'altro era API , ed entrambi hanno il loro script nei rispettivi package.jsonfile.

Quindi, ecco cosa ho fatto.

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

Ti piace la tua soluzione. Hanno anche UI ( node app) e API (angolare in una sottocartella src , suppongo sia cd src/ng serve), funziona solo la prima parte. Per esempio node app& cd src& ng serve.
Jeb50


1

Uso npm-run-all da un po 'di tempo, ma non ci sono mai andato d'accordo, perché l'output del comando in modalità watch non funziona bene insieme. Ad esempio, se inizio create-react-appejest in modalità orologio, sarò in grado di vedere solo l'output dell'ultimo comando che ho eseguito. Quindi la maggior parte delle volte, stavo eseguendo tutti i miei comandi manualmente ...

Per questo motivo, implemento la mia lib, run-screen . È ancora un progetto molto giovane (da ieri: p) ma potrebbe valere la pena guardarlo, nel tuo caso sarebbe:

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

Quindi premi il tasto numerico 1per vedere l'output di wp-servere premi 0per vedere l'output di start-watch.


1

La mia soluzione è simile a quella di Piittis, anche se ho avuto dei problemi con Windows. Quindi ho dovuto convalidare per win32.

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

Script di nodo semplice per iniziare senza troppe seccature. Utilizzo di readline per combinare gli output in modo che le linee non vengano alterate.

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)"

questo lavoro in windows

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.