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.
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\""
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"
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"
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.
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.
Une meilleure solution consiste à utiliser &
"dev": "npm run start-watch & npm run wp-server"
Si vous remplacez la double esperluette par une seule esperluette, les scripts seront exécutés simultanément.
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 pournpm-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 -- {*}\" --",
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!
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.
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:
Si vous n'êtes pas sous Windows, les outils/techniques Unix fonctionnent souvent bien pour réaliser quelque chose avec les scripts Node car:
Les modules pour les tâches système sous Nodeland sont aussi souvent des abstractions ou des approximations des outils Unix, de fs
à streams
.
Vous pouvez utiliser un &
pour le script d'exécution parallèle
"dev": "npm run start-watch & npm run wp-server"
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.
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));
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
});
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
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
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
.
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&
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);
});