web-dev-qa-db-fra.com

Comment puis-je exécuter plusieurs scripts NPM en parallèle?

Dans mon package.json, j'ai ces deux scripts:

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

Je dois exécuter ces 2 scripts en parallèle chaque fois que je commence à développer dans Node.js. La première chose à laquelle j'ai pensé a été d'ajouter un troisième script comme celui-ci:

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

... mais cela attendra que start-watch se termine avant d'exécuter wp-server.

Comment puis-je les exécuter en parallèle? S'il vous plaît gardez à l'esprit que j'ai besoin de voir la output de ces commandes. De plus, si votre solution implique un outil de génération, je préfère utiliser gulp au lieu de grunt car je l'utilise déjà dans un autre projet.

361
André Pena

Utilisez un package appelé simultanément .

npm i concurrently --save-dev

Puis configurez votre tâche npm run dev comme suit:

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

L'utilisation du package Concurrently fonctionne, mais vous n'en avez pas besoin pour accomplir cela. Vous pouvez simplement utiliser un canal sur des machines UNIX pour exécuter des tâches simultanées. Je suggérerais cette méthode à l’autre car elle vous évitera d’ajouter une dépendance supplémentaire.

"dev": "npm run start-watch | npm run wp-server"
276
Patrick Burtchaell

Si vous utilisez un environnement de type UNIX, utilisez simplement & comme séparateur: 

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

Sinon, si vous êtes intéressé par une solution multiplate-forme, vous pouvez utiliser npm-run-all module:

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

Depuis windows cmd, vous pouvez utiliser start :

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

Chaque commande lancée de cette façon commence dans sa propre fenêtre.

51
o.v.

Vous devez utiliser npm-run-all (ou concurrently, parallelshell), car il permet de mieux contrôler les commandes de démarrage et d’exécution. Les opérateurs &, | sont de mauvaises idées car vous devrez l’arrêter manuellement une fois tous les tests terminés.

Voici un exemple de test de rapporteur via 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 = Exécuter des commandes en parallèle.

-r = Tuez toutes les commandes lorsque l'une d'entre elles se termine avec un code de sortie égal à zéro.

Lancer npm run test lancera le pilote Selenium, démarrera le serveur http (pour vous servir des fichiers) et exécutera des tests de rapporteur. Une fois tous les tests terminés, le serveur http et le pilote Selenium seront fermés.

38
nir

Une meilleure solution consiste à utiliser &

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

Si vous remplacez la double esperluette par une seule esperluette, les scripts seront exécutés simultanément. 

10
Neil Girardi

J'ai vérifié presque toutes les solutions ci-dessus et seulement avec npm-run-all j'ai pu résoudre tous les problèmes. Le principal avantage par rapport à toutes les autres solutions est la possibilité de exécuter un script avec des arguments .

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

Note run-p est un raccourci pour npm-run-all --paraller

Cela me permet d’exécuter des commandes avec des arguments tels que npm run test:watch -- Something.

MODIFIER:

Il y a encore une option utile pour 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.

Ajoutez -r à votre script npm-run-all pour tuer tous les processus quand on a fini avec le code 0. Cela est particulièrement utile lorsque vous exécutez un serveur HTTP et un autre script utilisant le serveur.

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

J'ai une solution crossplatform sans modules supplémentaires . Je cherchais quelque chose comme un bloc catch try que je pourrais utiliser à la fois dans le cmd.exe et dans le bash. 

La solution est command1 || command2 qui semble fonctionner dans les deux environnements identiques. La solution pour le PO est donc:

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

Alors les simples npm start (et npm run dev) fonctionneront sur toutes les plateformes!

7
Entity Black
npm-run-all --parallel task1 task2

modifier:

Vous devez avoir npm-run-all préalablement installé. Vérifiez également cette page pour d’autres scénarios d’utilisation.

5
noego

Solution rapide

Dans ce cas, je dirais le meilleur pari Si ce script concerne un module privé destiné à ne s'exécuter que sur des machines * nix , vous pouvez utiliser l'opérateur de contrôle pour la création de processus, qui ressemble à ceci: &

Un exemple de cela dans un fichier package.json partiel:

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

Vous les exécuteriez ensuite en parallèle via npm run serve-bundle. Vous pouvez améliorer les scripts pour exporter les pids du processus forké dans un fichier comme ceci:

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

Quelque chose comme Google, opérateur de contrôle bash forking, pour en savoir plus sur son fonctionnement. J'ai également fourni un contexte supplémentaire concernant l'utilisation des techniques Unix dans les projets de nœud ci-dessous:

Autre contexte RE: Unix Tools & Node.js

Si vous n'êtes pas sous Windows, les outils/techniques Unix fonctionnent souvent bien pour réaliser quelque chose avec les scripts Node car: 

  1. Une grande partie de Node.js imite avec amour les principes Unix
  2. Vous êtes sur * nix (y compris OS X) et NPM utilise quand même un shell

Les modules pour les tâches système sous Nodeland sont aussi souvent des abstractions ou des approximations des outils Unix, de fs à streams.

5
james_womack

Vous pouvez utiliser un & pour le script d'exécution parallèle

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

Lien de référence

3
Behnam Mohammadi

Pourquoi pas

Une autre option permettant d’exécuter plusieurs scripts de nœuds consiste à utiliser un seul script de nœud, qui peut fork en beaucoup d’autres. Le fork est pris en charge de manière native dans Node, il n’ajoute donc aucune dépendance et est multi-plateforme.


Exemple minimal

Cela exécuterait simplement les scripts tels quels et supposerait qu'ils se trouvaient dans le répertoire du script parent.

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

Exemple verbeux

Cela exécuterait les scripts avec des arguments et configurés selon les nombreuses options disponibles.

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

Communication avec des scripts forkés

Forking présente également l'avantage supplémentaire que le script parent peut recevoir des événements des processus enfants forkés, ainsi que les renvoyer. Un exemple courant est que le script parent tue ses enfants forkés.

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

Pour plus d'événements et de méthodes disponibles, voir ChildProcess documentation

2
Boaz

J'ai rencontré des problèmes avec & et |, lesquels statuts de sortie et erreur renvoyée, respectivement.

D'autres solutions veulent exécuter n'importe quelle tâche avec un nom donné, comme npm-run-all, ce qui n'était pas mon cas d'utilisation.

J'ai donc créé npm-run-parallel qui exécute les scripts npm de manière asynchrone et rend compte lorsqu'ils sont terminés.

Donc, pour vos scripts, ce serait:

npm-run-parallel wp-server start-watch

2
ian

J'utilise npm-run-all depuis un certain temps, mais je ne me suis jamais bien entendu, car la sortie de la commande en mode veille ne fonctionne pas bien ensemble. Par exemple, si je lance create-react-app et jest en mode veille, je ne pourrai voir que le résultat de la dernière commande que j'ai exécutée. Donc, la plupart du temps, j'exécutais toutes mes commandes manuellement ...

C'est pourquoi, j'implémente ma propre bibliothèque, run-screen . C'est encore un projet très jeune (d'hier: p) mais il serait peut-être pire de le regarder, dans votre cas, ce serait:

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

Ensuite, vous appuyez sur la touche numérique 1 pour afficher le résultat de wp-server et appuyez sur 0 pour afficher le résultat de start-watch.

1
Alexandre

Dans mon cas, j'ai deux projets, l'un étaitUIet l'autreAPI, et les deux ont leur propre script dans leurs fichiers package.json respectifs.

Alors, voici ce que j'ai fait.

npm run --prefix react start&  npm run --prefix express start&
0
Vikash Mishra

Un script de noeud simple pour vous permettre de partir sans trop de tracas. Utiliser readline pour combiner les sorties afin que les lignes ne soient pas mutilées.

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
Piittis