Как запустить несколько сценариев npm параллельно?

в своем package.json у меня есть эти два сценария:

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

Я должен запустить эти 2 скрипта параллельно каждый раз, когда я начинаю развиваться в узел.js. Первое, о чем я подумал, это добавить третий скрипт, подобный этому:

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

... но это подождет start-watch чтобы закончить перед запуском wp-server.

как я могу запустить их параллельно? пожалуйста, имейте в виду, что мне нужно увидеть output из этих команд. Кроме того, если ваш решение включает в себя инструмент сборки, я бы предпочел использовать gulp вместо grunt потому что я уже использовать его в другом проекте.

14 ответов


использовать пакет под названием по совместительству.

npm i concurrently --save-dev

затем Настройки npm run dev задач как так:

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

использование параллельного пакета работает, но для этого он вам не нужен. Вы можете просто использовать канал на машинах на базе UNIX, выполняющих параллельные задачи. Я бы предложил этот метод над другим, потому что он избавляет вас от необходимости добавлять дополнительную зависимость.

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

Если вы используете UNIX-подобную среду, просто используйте & в качестве разделителя:

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

В противном случае, если вы заинтересованы в кросс-платформенном решении, вы можете использовать npm-run-all модуль:

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

из Windows cmd вы можете использовать start:

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

каждая команда, запущенная таким образом, запускается в своем собственном окне.


вы должны использовать 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-сервер и драйвер selenium.


лучшее решение-использовать &

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

Я проверил почти все решения сверху и только с npm-run-all я смог решить все проблемы. Главное преимущество перед всеми другими решениями-это возможность запустить скрипт с аргументами.

{
  "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 --paraller

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

EDIT:

есть еще один полезный опции на 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 -- {*}\" --",

Если вы замените двойной амперсанд одним амперсандом, сценарии будут выполняться одновременно.


у меня есть crossplatform решение без каких-либо дополнительных модулей. Я искал что-то вроде блока try catch, который я мог бы использовать в cmd.exe и в bash.

решение command1 || command2 который, кажется, работает в обеих средах одинаковы. Таким образом, решение для 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"
}

потом просто npm startnpm run dev) будет работать на всех платформах!


Быстрый Решение

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

пример выполнения этого в частичном пакете.файл 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. Вы можете улучшить сценарии для вывода pids раздвоенный процесс в файл, например:

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

Google что-то вроде оператор управления bash для раздвоения чтобы узнать больше о том, как он работает. Я также предоставил некоторый дополнительный контекст относительно использования методов Unix в проектах узлов ниже:

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

если вы не на Windows, Unix инструменты / методы часто работают хорошо, чтобы достичь чего-то со скриптами узлов, потому что:

  1. много Узел.js с любовью имитирует принципы Unix
  2. вы на *nix (ВКЛ. OS X) и NPM использует оболочку в любом случае
для системных задач в Nodelandбыл также часто абстракций и допущений из инструментов Unix, с fs до streams.

npm-run-all --parallel task1 task2

изменить:

вам нужно npm-run-all заранее установлена. Также проверьте на этой странице для других сценариев использования.


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

другие решения хотят запускать любую задачу с заданным именем, например npm-run-all, что не было моим вариантом использования.

Итак, я создал npm-run-parallel который запускает сценарии npm асинхронно и сообщает, когда они закончены.

Итак, для ваших сценариев это будет:

npm-run-parallel wp-server start-watch


как насчет разветвления

другой вариант запуска нескольких сценариев узлов - это сценарий с одним узлом, который может вилки многие другие. Разветвление поддерживается изначально в узле, поэтому оно не добавляет зависимостей и является кросс-платформенным.


минимальный пример

это просто запускает скрипты как есть и предполагает, что они находятся в каталоге родительского скрипта.

// 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 документация


в моем случае у меня есть два проекта, Один был UI, а другой API, и оба имеют свой собственный сценарий в своих соответствующих package.json файлы.

Итак, вот что я сделал.

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