Як я можу паралельно запускати кілька сценаріїв npm?


542

У package.jsonмене є два сценарії:

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

Мені доводиться паралельно запускати ці 2 сценарії кожного разу, коли я починаю розробляти в Node.js. Перше, що я подумав, це додати третій сценарій, подібний до цього:

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

... але це буде чекати, коли start-watchзакінчиться, перш ніж бігти wp-server.

Як я можу запустити їх паралельно? Будь ласка, майте на увазі, що мені потрібно переглянути outputці команди. Крім того, якщо ваше рішення включає інструмент збирання, я б краще використовувати gulpзамість того, gruntщо я вже використовую його в іншому проекті.


23
&&запускатиме сценарії послідовно, а паралельно& виконуватиме їх .
vsync

Швидкий спосіб зробити це npm run start-watch & npm run wp-server. Це запустить першу команду як фоновий потік. Це дуже добре працює, коли одна з команд не працює довго і пізніше її не потрібно виконувати вручну. Щось подібне concurrentlyдозволяє одночасно знищити всі потоки за допомогою CTRL-C.
Джошуа Пінтер

Відповіді:


616

Використовуйте пакет, який називається одночасно .

npm i concurrently --save-dev

Потім налаштуйте npm run devзавдання так:

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

11
node ./node_modules/concurrently/src/main.jsне потрібна. concurrentбуде працювати нормально в сценаріях , так як модуль встановлює бункер для./node_modules/.bin/concurrent
Рейн

14
Існує також паралельна оболонка . Я на насправді рекомендую , що один , як concurrentlyвикористовує кілька потоків, зв'язуйтеся з виходом консолі (колір може йти дивно, курсор пішов) , а parallelshellНЕ це питання .
Штійн де Вітт

3
Помилки, які паралельно згадували @StijndeWitt, тепер були виправлені у версії 2.0.0 . Ви можете використовувати --rawрежим для збереження кольорів у виході.
Кіммо

23
@StijndeWitt паралельна оболонка була застаріла на користь npm-run-all github.com/keithamus/…
jtzero

12
Має бути кращий спосіб для управління сценаріями побудови / запуску Javascript. Все на цій платформі, здається, пов'язане разом. котирування з уникнутими котируваннями та npm-побудовами для виклику інших "npm run" збірок. Це стає досить болісно.
Ендрю Т Фіннелл

141

Якщо ви використовуєте середовище, схоже на UNIX, просто використовуйте &як роздільник:

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

В іншому випадку, якщо вам цікаво крос-платформене рішення, ви можете використовувати модуль npm-run-all :

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

14
Я роблю це - час від часу, коли я "ctrl-c" npm, команда продовжує зависати на задньому плані ... Будь-які ідеї?
Kamil Tomšík

13
a && bпочинається bпісля aуспішного завершення, але nodemon ніколи не припиняється без помилок, тому це не може працювати. a & bзапускає a, переміщує його на другий план і починає bвідразу. Виграй! a | bтруби, виступ яких aдо стдіну bвимагає обох виконання одночасно. Хоча це може здатися бажаним ефектом, не слід його використовувати тут.
j2L4e

8
@ KamilTomšík &- це дійсно погана ідея, оскільки вона деталізує процес. Це означає, що це npmвже не буде батьківським процесом. Ви закінчите зомбі, з npm run start-watchяким не будете вбивати ctrl-c.
ngryman

6
Просто додайте, waitщоб пом'якшити проблему з висячими процесами:"dev": "npm run start-watch & npm run wp-server & wait"
Руслан Прокопчук

2
Це не зомбі. Але &на unix заважає команді відповідати на Cc / Cz, а також запобігає поширенню коду повернення у разі відмови.
бінкі

77

З Windows cmd ви можете використовувати start:

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

Кожна команда, запущена таким чином, починається у власному вікні.


2
Ідеальне рішення! Мені подобається, що воно запускає нове вікно. Відмінно підходить для потреб VS2015 package.json
TetraDev

13
Це не працює, якщо у вас є завдання спостерігача, тому що &&чекає, коли перша команда завершиться перед запуском другої команди, і завдання спостерігача ніколи не закінчиться.
Бенні Нойгебауер

2
@BennyNeugebauer Командам передує команда "start", яка відкриває новий командний рядок для кожної з команд. Спочатку я також плутався, бо думав, що "використання оператора && не працюватиме". Це рішення дуже просте і не вимагає додаткових пакунків / робіт від розробника.
Аддісон

5
Це неправильно. Команда буде виконуватися послідовно. У Windows вам потрібно використовувати плагін, щоб одночасно запускати команди.
zhekaus

1
Це не специфічно для Windows?
бінкі

62

Ви повинні використовувати npm-run-all (або concurrently, parallelshell), оскільки він має більше контролю над командами запуску та вбивання. Оператори &,| це погані ідеї, оскільки вам потрібно буде вручну зупинити це після закінчення всіх тестів.

Це приклад тестування транспортира через 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 = Виконувати команди паралельно.

-r = Убийте всі команди, коли одна з них закінчується кодом виходу нуля.

Запуск npm run testзапустить драйвер Selenium, запустить http-сервер (для обслуговування файлів) та запустить тести транспортування. Як тільки всі тести будуть закінчені, він закриє http-сервер і драйвер селену.


3
Цікаво, як це справно працює для запуску тестів. Хоча webdriver-start і http-сервер можуть працювати паралельно, завдання транспортування має виконуватися лише після перших двох.
asenovm

@asenovm для завдань, що залежать від замовлення, чому б не просто використовувати gulpі gulp-sync?
r3wt

30

Ви можете використовувати його &для паралельного виконання сценарію

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

Довідкова посилання


Це також буде працювати в Windows? Вибачте, я досить новачок у вузлі, і не знаю, як це перевірити!
Бенісон Сем

@BenisonSam ні, працює на Mac хоч
shanehoban

25

Кращим рішенням є використання &

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

54
Ні, це не краще, тому що це працює не на всіх платформах.
Штійн де Віт

Я не знаю, що. На яких платформах вона не працює? @Corey - оновіть свою відповідь попередженням про інтер-оп, і я вас запрошую
Ешлі Coolman,

8
&працює в Windows, але він працює інакше. В OSX він буде виконувати обидві команди одночасно, але в Windows він виконає першу команду, а після існування першої команди - запустить другу.
Тревор

3
Ні, це не так, як він відокремлює процес, ви не зможете його вбити просто.
ngryman

2
@ngryman Це я теж очікував. Однак я спробував це, і це вбиває всі три процеси (dev, start-watch і wp-сервер), коли ви натискаєте Ctrl + C.
musicin3d

17

Я перевірив майже всі рішення зверху і лише за допомогою npm-run - все, що я міг вирішити всі проблеми. Основна перевага перед усіма іншими рішеннями - це можливість запускати скрипт з аргументами .

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

Примітка run-p- це ярлик дляnpm-run-all --parallel

Це дозволяє мені запускати команду з такими аргументами npm run test:watch -- Something .

Редагувати:

Є ще один корисний варіант для 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.

Додайте -rдо свого npm-run-allскрипту, щоб знищити всі процеси, коли завершено з кодом 0. Це особливо корисно, коли ви запускаєте сервер HTTP та інший сценарій, який використовує сервер.

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

15

У мене є розробка платформ без додаткових модулів . Я шукав щось на зразок блоку спробу вловлювання, який би я міг використовувати як у cmd.exe, так і в bash.

Рішення полягає в тому, command1 || command2що, здається, працює в обох середовищах однаково. Тож рішенням для ОП є:

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

Тоді прості npm startnpm run dev) працюватимуть на всіх платформах!


11

Якщо ви заміните подвійну амперсанд на одну амперсанду, скрипти виконуватимуться одночасно.


Точно, це просто і елегантно, не потрібно залежностей чи іншої магії.
magikMaker

1
@Ginzburg Оскільки працює не однаково для всіх платформ, як ви бачите в інших відповідях.
Хорхе Фуентес Гонсалес

6

Швидке рішення

У цьому випадку я б сказав найкраще, якщо цей скрипт призначений для приватного модуля, призначеного для роботи лише на * nix-машинах , ви можете використовувати керуючий оператор для розгортання процесів, який виглядає приблизно так:&

Приклад цього в частковому файлі package.json:

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

Потім ви виконаєте їх обидва паралельно через npm run serve-bundle. Ви можете покращити сценарії, щоб виводити приводи роздвоєного процесу у такий файл:

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

Google щось на зразок оператора управління bash для розгортання щоб дізнатися більше про те, як він працює. Нижче я також надав додатковий контекст щодо використання методів Unix у проектах Node:

Подальший контекст RE: Unix Tools & Node.js

Якщо ви не в Windows, інструменти / методи Unix часто добре допомагають досягти чогось із сценаріїв Node, оскільки:

  1. Значна частина Node.js з любов'ю імітує принципи Unix
  2. Ви перебуваєте на * nix (включаючи ОС X), і NPM так чи інакше використовує оболонку

Модулі для системних завдань у Nodeland також часто є абстракціями або наближеннями інструментів Unix, від fsдо streams.


1
Ні, оскільки &оператор не підтримується в Windows.
Штійн де Вітт

3
@StijndeWitt мій пост говорить "Якщо ви не в Windows ...". 0% людей, з якими я працюю, в одній з найбільших технологічних компаній світу працює з Node на Windows. Тож явно мій пост все ще цінний багатьом розробникам.
james_womack

2
Це свого роду круговий спосіб міркування, чи не так? Якщо ви пишете такі npm-скрипти, як це, ви не зможете використовувати Windows, оскільки він не працюватиме. Тому ніхто не використовує Windows, тому не має значення, що він не працює ... Ви закінчуєте програмне забезпечення, залежне від платформи. Тепер, якщо справа, яку потрібно зробити, зробити дуже кросплатформою дуже важко, ніж це може бути непоганий компроміс. Але цю проблему тут дуже легко виконати зі стандартними сценаріями npm, такими як паралельно і паралельно .
Штійн де Вітт

2
@StijndeWitt Жодне з моїх міркувань не було круговим. Я зробив констатацію фактичних міркувань. Ми розміщуємо методи, спільні для розробників Node, багато з яких створюють та розгортають на серверах Linux. Так, він повинен працювати в Windows, якщо це сценарій користувача, але більшість сценаріїв npm призначені для розробки та розгортання - переважно на * nix-машинах. Щодо модулів, про які ви згадали: а) це величезна розтяжка, щоб викликати паралельно і паралельно "стандарт" (~ 1500 завантажень на день - це далеко не стандарт у NPMland); б) якщо вам потрібно додаткове програмне забезпечення для паралельного процесу, ви можете також використовувати Залп.
james_womack

@StijndeWitt Я вдячний, що мені відомо про ці модулі, дякую
james_womack


5

Як щодо роздвоєння

Ще один варіант запуску декількох сценаріїв Вузла - це один сценарій Вузла, який може розщедрити багато інших. Форкінг підтримується в Node, тому він не додає залежностей і є платформою.


Мінімальний приклад

Це просто запустить сценарії як є, і припустимо, що вони розташовані в директорії батьківського сценарію.

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

Докладний приклад

Це запустить сценарії з аргументами та налаштовано на безліч доступних опцій.

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

Спілкування з роздвоєними сценаріями

Форкінг також має додаткову перевагу в тому, що батьківський скрипт може приймати події з роздвоєних дочірніх процесів, а також надсилати назад. Поширений приклад - батьківський сценарій, щоб вбити своїх роздвоєних дітей.

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

Більш доступні події та методи див. У ChildProcessдокументації


3

Я зіткнувся з проблемами з &і| , які виходять із статусами та помилками виходу відповідно.

Інші рішення хочуть запустити будь-яку задачу з таким ім'ям, як npm-run-all, що не було моїм випадком використання.

Тож я створив npm-run-paralle, який запускає сценарії npm асинхронно і звітує про них, коли вони закінчені.

Отже, для ваших сценаріїв це буде:

npm-run-parallel wp-server start-watch


2

У моєму випадку у мене є два проекти, один - інтерфейс користувача, а інший - API , і в обох є власний сценарій у відповідних package.jsonфайлах.

Отже, ось що я зробив.

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

Як ваше рішення. Також є UI ( node app) та API (Angular у src підпапки , напевно, є cd src/ng serve), працює лише перша частина. Наприклад node app& cd src& ng serve.
Jeb50


1

Я вже деякий час використовую npm-run-all , але ніколи не погоджувався з цим, тому що вихід команди в режимі перегляду не працює добре разом. Наприклад, якщо я запускаю create-react-appіjest в режимі перегляду, я зможу бачити вихід лише з останньої команди, яку я запустив. Тож більшу частину часу я виконував усі свої команди вручну ...

Ось чому я реалізую власний ліб, запущений екран . Це ще дуже молодий проект (з вчорашнього дня: p), але, можливо, варто його переглянути, у вашому випадку це буде:

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

Потім натисніть цифрову клавішу, 1щоб побачити вихід, wp-serverі натисніть, 0щоб побачити вихід start-watch.


1

Моє рішення схоже на Piittis ', хоча у мене були проблеми з Windows. Тому мені довелося перевірити на 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

Простий скрипт із вузлом, щоб ви проходили без зайвих клопотів. Використовуючи лінію читання для комбінування результатів, щоб рядки не заплутувалися.

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

ця робота у Windows

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.