Bagaimana saya bisa menjalankan beberapa skrip npm secara paralel?

543

Di saya, package.jsonsaya punya dua skrip ini:

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

Saya harus menjalankan 2 skrip ini secara paralel setiap kali saya mulai mengembangkan di Node.js. Hal pertama yang saya pikirkan adalah menambahkan skrip ketiga seperti ini:

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

... tapi itu akan menunggu start-watchsampai selesai sebelum berjalan wp-server.

Bagaimana saya bisa menjalankan ini secara paralel? Harap diingat bahwa saya perlu melihat outputperintah-perintah ini. Juga, jika solusi Anda melibatkan alat bangun, saya lebih suka menggunakan gulpdaripada gruntkarena saya sudah menggunakannya di proyek lain.

André Pena
sumber
23
&&akan menjalankan skrip Anda secara berurutan sementara &akan menjalankannya secara paralel .
vsync
Cara cepat untuk melakukannya adalah npm run start-watch & npm run wp-server. Ini akan menjalankan perintah pertama sebagai utas latar. Ini bekerja dengan sangat baik ketika salah satu perintah tidak berjalan lama dan tidak perlu keluar secara manual nanti. Sesuatu seperti concurrentlymemungkinkan Anda untuk membunuh semua utas secara bersamaan dengan CTRL-C.
Joshua Pinter

Jawaban:

617

Gunakan paket yang disebut bersamaan .

npm i concurrently --save-dev

Kemudian atur npm run devtugas Anda seperti itu:

"dev": "concurrently --kill-others \"npm run start-watch\" \"npm run wp-server\""
Neil Kistner
sumber
11
node ./node_modules/concurrently/src/main.jstidak dibutuhkan. concurrentakan berfungsi dengan baik dalam skrip karena modul menginstal bin to./node_modules/.bin/concurrent
raine
14
Ada juga paralelshell . Saya benar-benar merekomendasikan yang concurrentlymenggunakan beberapa stream yang berantakan dengan output konsol (warna mungkin aneh, kursor hilang) sedangkan parallelshelltidak memiliki masalah itu .
Stijn de Witt
3
Bug yang disebutkan secara bersamaan oleh @StijndeWitt kini telah diperbaiki pada rilis 2.0.0 . Anda dapat menggunakan --rawmode untuk mempertahankan warna dalam output.
Kimmo
23
@StijndeWitt parallelshell telah ditinggalkan karena npm-run-all github.com/keithamus/…
jtzero
12
Harus ada cara yang lebih baik bagi kita untuk mengelola skrip Javascript build / run. Segala sesuatu untuk platform ini tampaknya disatukan. kutipan dengan tanda kutip dan npm build untuk memanggil build 'npm run' lainnya .. Ini semakin menyakitkan.
Andrew T Finnell
142

Jika Anda menggunakan lingkungan seperti UNIX, cukup gunakan &sebagai pemisah:

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

Kalau tidak, jika Anda tertarik pada solusi lintas platform, Anda bisa menggunakan modul npm-run-all :

"dev": "npm-run-all --parallel start-watch wp-server"
Diogo Cardoso
sumber
14
Saya melakukan ini - dari waktu ke waktu ketika saya "ctrl-c" npm, perintah terus bertahan di latar belakang ... Ada ide?
Kamil Tomšík
13
a && bdimulai bsetelah aselesai dengan sukses, tetapi nodemon tidak pernah berhenti tanpa kesalahan, sehingga tidak bisa berfungsi. a & bdimulai a, pindahkan ke latar belakang dan blangsung mulai . Menang! a | bpipa stdout ake ke stdin byang membutuhkan keduanya berjalan secara bersamaan. Meskipun ini tampaknya memiliki efek yang diinginkan, Anda tidak boleh menggunakannya di sini.
j2L4e
8
@ KamilTomšík &adalah ide yang sangat buruk karena menghalangi proses. Ini berarti bahwa npmtidak akan menjadi proses induk lagi. Anda akan berakhir dengan zombie npm run start-watchyang tidak akan dibunuh ctrl-c.
ngryman
6
Tambahkan saja waituntuk mengurangi masalah dengan proses gantung:"dev": "npm run start-watch & npm run wp-server & wait"
Ruslan Prokopchuk
2
Itu bukan zombie. Tetapi &pada unix mencegah perintah menanggapi Cc / Cz dan juga mencegah kode kembali dari merambat jika terjadi kegagalan.
binki
77

Dari windows cmd Anda dapat menggunakan start:

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

Setiap perintah yang diluncurkan dengan cara ini dimulai di jendela sendiri.

Ov
sumber
2
Solusi sempurna! Saya suka itu meluncurkan jendela baru. Bagus untuk kebutuhan VS2015 package.json
TetraDev
13
Ini tidak berfungsi jika Anda memiliki tugas pengamat karena &&menunggu perintah pertama selesai sebelum memulai perintah kedua dan tugas pengamat tidak akan pernah selesai.
Benny Neugebauer
2
@ BennyNeugebauer Perintah diawali dengan perintah "mulai" yang membuka baris perintah baru untuk masing-masing perintah. Saya bingung pada awalnya juga karena saya pikir "menggunakan operator && tidak akan bekerja". Solusi ini sangat sederhana dan tidak memerlukan paket / pekerjaan tambahan dari pengembang.
Addison
5
Ini salah. Perintah akan dijalankan secara berurutan. Di Windows Anda harus menggunakan plugin untuk menjalankan perintah secara bersamaan.
zhekaus
1
Bukankah ini khusus Windows?
binki
62

Anda harus menggunakan npm-run-all (atau concurrently, parallelshell), karena ia memiliki kontrol lebih besar untuk memulai dan mematikan perintah. Operator &, |adalah ide buruk karena Anda harus menghentikannya secara manual setelah semua tes selesai.

Ini adalah contoh untuk pengujian busur derajat melalui 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 = Jalankan perintah secara paralel.

-r = Bunuh semua perintah ketika salah satu dari mereka selesai dengan kode keluar nol.

Menjalankan npm run testakan memulai driver Selenium, mulai server http (untuk melayani file Anda) dan menjalankan tes busur derajat. Setelah semua tes selesai, itu akan menutup server http dan driver selenium.

nir
sumber
3
Saya bertanya-tanya bagaimana ini bekerja dengan baik untuk menjalankan tes. Sementara webdriver-start dan http-server dapat berjalan secara paralel, tugas busur derajat hanya akan berjalan setelah dua yang pertama.
asenovm
@asenovm untuk tugas-tugas yang tergantung pesanan, mengapa tidak hanya menggunakan gulpdan gulp-sync?
r3wt
30

Anda dapat menggunakan satu &untuk skrip run paralel

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

Tautan referensi

Behnam Mohammadi
sumber
Apakah ini juga berfungsi di Windows? Maaf, saya cukup baru di simpul dan saya tidak tahu cara memverifikasi ini!
Benison Sam
@BenisonSam tidak, bekerja di Mac
shanehoban
25

Solusi yang lebih baik adalah menggunakan &

"dev": "npm run start-watch & npm run wp-server"
Corey
sumber
54
Tidak, ini tidak lebih baik karena tidak bekerja di semua platform.
Stijn de Witt
Saya tidak tahu hal itu. Platform apa yang tidak berfungsi? @Corey - perbarui jawaban Anda dengan peringatan di antar-op dan saya akan
mendukung
8
&berfungsi pada Windows, tetapi bekerja secara berbeda. Pada OSX, itu akan menjalankan kedua perintah secara bersamaan, tetapi pada Windows, itu akan menjalankan perintah pertama, dan setelah perintah pertama ada, itu akan menjalankan perintah kedua.
Trevor
3
Tidak, itu tidak akan menghilangkan prosesnya, Anda tidak akan bisa membunuhnya dengan cara yang sederhana.
ngryman
2
@ ngryman Itulah yang saya harapkan juga. Namun, saya mencoba ini dan itu membunuh ketiga proses (dev, start-watch, dan wp-server) ketika Anda menekan Ctrl + C.
musicin3d
17

Saya sudah memeriksa hampir semua solusi dari atas dan hanya dengan npm-run-semua saya bisa menyelesaikan semua masalah. Keuntungan utama dari semua solusi lainnya adalah kemampuan untuk menjalankan skrip dengan argumen .

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

Catatan run-padalah jalan pintas untuknpm-run-all --parallel

Ini memungkinkan saya untuk menjalankan perintah dengan argumen seperti npm run test:watch -- Something.

EDIT:

Ada satu opsi lagi yang bermanfaat untuk 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.

Tambahkan -rke npm-run-allskrip Anda untuk mematikan semua proses ketika satu selesai dengan kode 0. Ini sangat berguna ketika Anda menjalankan server HTTP dan skrip lain yang menggunakan server.

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

Saya punya solusi lintas platform tanpa modul tambahan . Saya sedang mencari sesuatu seperti try catch block yang bisa saya gunakan di cmd.exe dan di bash.

Solusinya adalah command1 || command2yang tampaknya bekerja di kedua lingkungan yang sama. Jadi solusi untuk OP adalah:

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

Maka sederhana npm start(dan npm run dev) akan bekerja di semua platform!

Entity Black
sumber
11

Jika Anda mengganti ampersand ganda dengan ampersand tunggal, skrip akan berjalan bersamaan.

Neil Girardi
sumber
Tepat, sederhana dan elegan, tidak perlu untuk dependensi atau sihir lainnya.
magikMaker
1
@Ginzburg Karena tidak bekerja sama untuk semua platform, seperti yang Anda lihat di jawaban lain
Jorge Fuentes González
6

Solusi Cepat

Dalam hal ini, saya akan mengatakan taruhan terbaik Jika skrip ini adalah untuk modul pribadi yang dimaksudkan untuk berjalan hanya pada mesin berbasis * nix , Anda dapat menggunakan operator kontrol untuk proses forking, yang terlihat seperti ini:&

Contoh melakukan ini dalam file package.json parsial:

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

Anda kemudian akan menjalankan keduanya secara paralel melalui npm run serve-bundle. Anda dapat meningkatkan skrip untuk menampilkan pids dari proses bercabang menjadi file seperti ini:

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

Google sesuatu seperti operator kontrol bash untuk forking untuk mempelajari lebih lanjut tentang cara kerjanya. Saya juga telah memberikan beberapa konteks lebih lanjut tentang memanfaatkan teknik Unix dalam proyek Node di bawah ini:

Konteks Lebih Lanjut RE: Unix Tools & Node.js

Jika Anda tidak menggunakan Windows, alat / teknik Unix sering bekerja dengan baik untuk mencapai sesuatu dengan skrip Node karena:

  1. Banyak Node.js dengan penuh kasih meniru prinsip-prinsip Unix
  2. Anda berada di * nix (termasuk OS X) dan NPM tetap menggunakan shell

Modul untuk tugas sistem di Nodeland juga sering merupakan abstraksi atau perkiraan alat Unix, dari fshingga streams.

james_womack
sumber
1
Tidak, karena &operator tidak didukung di Windows.
Stijn de Witt
3
@StijndeWitt posting saya mengatakan "Jika Anda tidak menggunakan Windows ...". 0% dari orang-orang yang bekerja dengan saya, di salah satu perusahaan teknologi terbesar di dunia, menjalankan Node di Windows. Jadi jelas posting saya masih berharga bagi banyak pengembang.
james_womack
2
Ini semacam cara berpikir yang melingkar, bukan? Jika Anda menulis skrip npm Anda seperti ini, Anda tidak akan dapat menggunakan Windows karena itu tidak akan berfungsi. Jadi tidak ada yang menggunakan Windows, jadi tidak masalah itu tidak berfungsi ... Anda berakhir dengan perangkat lunak yang bergantung pada platform. Sekarang jika hal yang perlu dilakukan sangat sulit untuk dilakukan lintas-platform, daripada itu mungkin merupakan trade-off yang baik untuk dilakukan. Tapi masalah ini di sini adalah sangat mudah dilakukan dengan skrip NPM standar seperti bersamaan dan parallelshell .
Stijn de Witt
2
@StijndeWitt Tak satu pun dari alasan saya melingkar. Saya membuat pernyataan fakta tanpa alasan. Kami memposting teknik yang umum untuk pengembang Node, banyak di antaranya membangun & menyebarkan di server Linux. Ya, itu harus bekerja pada Windows jika ini adalah skrip userland, tetapi sebagian besar skrip npm adalah untuk pengembangan dan penyebaran — kebanyakan di mesin * nix. Mengenai modul yang Anda sebutkan a) sangat sulit untuk memanggil secara bersamaan dan paralelkan "standar" (~ 1500 unduhan sehari jauh dari standar di NPMland) dan b) jika Anda memerlukan perangkat lunak tambahan untuk proses paralel, sebaiknya Anda juga menggunakan Teguk.
james_womack
@StijndeWitt Saya menghargai kesadaran akan modul-modul itu — terima kasih
james_womack
6
npm-run-all --parallel task1 task2

edit:

Anda harus menginstal npm-run-all terlebih dahulu. Periksa juga halaman ini untuk skenario penggunaan lainnya.

noego
sumber
5

Bagaimana dengan forking

Pilihan lain untuk menjalankan beberapa skrip Node adalah dengan skrip Node tunggal, yang dapat memotong banyak yang lain. Forking didukung secara native di Node, sehingga tidak menambah ketergantungan dan bersifat lintas-platform.


Contoh minimal

Ini hanya akan menjalankan skrip apa adanya dan menganggap skrip tersebut berada di direktori skrip induk.

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

Contoh verbose

Ini akan menjalankan skrip dengan argumen dan dikonfigurasi oleh banyak opsi yang tersedia.

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

Berkomunikasi dengan skrip bercabang dua

Forking juga memiliki manfaat tambahan bahwa skrip induk dapat menerima acara dari proses anak bercabang ulang serta mengirim kembali. Contoh umum adalah skrip induk untuk membunuh anak-anak bercabang dua.

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

Untuk acara dan metode lainnya yang tersedia, lihat ChildProcessdokumentasi

Boaz - Pasang kembali Monica
sumber
3

Saya mengalami masalah dengan &dan| , yang keluar status dan kesalahan melempar, masing-masing.

Solusi lain ingin menjalankan tugas apa pun dengan nama yang diberikan, seperti npm-run-all, yang bukan kasus penggunaan saya.

Jadi saya membuat npm-run-parallel yang menjalankan skrip npm secara asinkron dan melaporkan kembali ketika sudah selesai.

Jadi, untuk skrip Anda, itu akan menjadi:

npm-run-parallel wp-server start-watch

ian
sumber
2

Dalam kasus saya, saya memiliki dua proyek, satu adalah UI dan yang lainnya adalah API , dan keduanya memiliki skrip masing-masingpackage.json file .

Jadi, inilah yang saya lakukan.

npm run --prefix react start&  npm run --prefix express start&
Vikash Mishra
sumber
Suka solusi Anda. Juga memiliki UI ( node app) dan API (Angular dalam src subfolder , tebak cd src/ng serve), hanya bagian pertama yang berfungsi. Sebagai contoh node app& cd src& ng serve.
Jeb50
1

Saya telah menggunakan npm-run-all untuk beberapa waktu, tetapi saya tidak pernah cocok dengannya, karena output dari perintah dalam mode menonton tidak bekerja dengan baik bersama-sama. Misalnya, jika saya memulai create-react-appdanjest dalam mode tontonan, saya hanya akan dapat melihat output dari perintah terakhir yang saya jalankan. Jadi sebagian besar waktu, saya menjalankan semua perintah saya secara manual ...

Inilah sebabnya, saya mengimplementasikan lib saya sendiri, run-screen . Ini masih proyek yang sangat muda (dari kemarin: p) tetapi mungkin layak untuk melihatnya, dalam kasus Anda itu akan menjadi:

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

Kemudian Anda menekan tombol angka 1untuk melihat output wp-serverdan tekan 0untuk melihat output start-watch.

Alexandre
sumber
1

Solusi saya mirip dengan Piittis, meskipun saya punya beberapa masalah dalam menggunakan Windows. Jadi saya harus memvalidasi untuk 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");
})();

sumber
0

Script simpul sederhana untuk membuat Anda pergi tanpa terlalu banyak kesulitan. Menggunakan readline untuk menggabungkan output sehingga garis tidak rusak.

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);
});
Piittis
sumber
0
"dev": "(cd api && start npm run start) & (cd ../client && start npm run start)"

ini bekerja di windows

SB3NDER
sumber