Отправка аргументов командной строки в скрипт npm

821

scriptsЧасть моего в package.jsonнастоящее время выглядит следующим образом :

"scripts": {
    "start": "node ./script.js server"
}

... что означает, что я могу запустить, npm startчтобы запустить сервер. Все идет нормально.

Тем не менее, я хотел бы иметь возможность запустить что-то вроде npm start 8080и передать аргумент (например) script.js(например npm start 8080=> node ./script.js server 8080). Это возможно?

arnemart
источник

Ответы:

1133

Изменить 2014.10.30: есть возможность передавать аргументы с npm runnpm 2.0.0

Синтаксис выглядит следующим образом:

npm run <command> [-- <args>]

Обратите внимание на необходимое --. Необходимо разделить параметры, передаваемые npmсамой команде, и параметры, передаваемые вашему сценарию.

Так что если у вас есть в package.json

"scripts": {
    "grunt": "grunt",
    "server": "node server.js"
}

Тогда следующие команды будут эквивалентны:

grunt task:target => npm run grunt -- task:target

node server.js --port=1337 => npm run server -- --port=1337

Чтобы получить значение параметра, см. Этот вопрос . Для чтения именованных параметров, вероятно, лучше всего использовать библиотеку синтаксического анализа, такую ​​как yargs или minimist ; nodejs предоставляет process.argvглобально, содержащий значения параметров командной строки, но это низкоуровневый API (массив строк, разделенных пробелами, предоставляемый операционной системой для исполняемого файла узла).


Изменить 2013.10.03: в настоящее время это невозможно напрямую. Но есть связанная проблема GitHub, открытаяnpm для реализации запрашиваемого вами поведения. Кажется, консенсус заключается в том, чтобы это реализовать, но это зависит от другой проблемы, решаемой ранее.


Исходный ответ: В качестве некоторого обходного пути (хотя и не очень удобного) вы можете сделать следующее:

Назовите название вашего пакета от package.jsonis, myPackageи у вас также есть

"scripts": {
    "start": "node ./script.js server"
}

Затем добавьте package.json:

"config": {
    "myPort": "8080"
}

И в вашем script.js:

// defaulting to 8080 in case if script invoked not via "npm run-script" but directly
var port = process.env.npm_package_config_myPort || 8080

Таким образом, по умолчанию npm startбудет использоваться 8080. Однако вы можете настроить его (значение будет сохранено npmво его внутренней памяти):

npm config set myPackage:myPort 9090

Затем при вызове npm startбудет использоваться 9090 ( package.jsonпереопределяется значение по умолчанию ).

jakub.g
источник
1
Это также прекрасно работает вместе с такими пакетами, как yargs; все параметры после --могут быть проанализированы в вашем скрипте.
Томас
11
AFAIKS, это только позволяет добавлять параметры в конец ваших скриптов .. что если вам нужны параметры в середине?
Спок
109
-- --argsсвятое дерьмо , что это странно , но хорошо
Август
9
@Spock Вы можете использовать функции оболочки. Вот настройка eslint + tslint, которую я использую, чтобы разрешить передачу пользовательских аргументов в eslint, например, через «npm run lint - -f unix»: «lint»: «f () {eslint -f codeframe $ @. && npm run tslint && echo 'lint clean!';}; f "
ecmanaut
3
Лучший способ установить значение «myPackage: myPort 9090» с помощью флага конфигурации для команды «--myPackage: myPort = 9090» - keithcirkel.co.uk/how-to-use-npm-as-a-build -инструмент
chrismarx
223

Вы просили, чтобы иметь возможность запустить что-то вроде npm start 8080 . Это возможно без необходимости изменения script.jsили конфигурации файлов следующим образом.

Например, в вашем "scripts"значении JSON, включите:

"start": "node ./script.js server $PORT"

А затем из командной строки:

$ PORT=8080 npm start

Я подтвердил, что это работает, используя bash и npm 1.4.23. Обратите внимание, что этот обходной путь не требует решения проблемы GitHub npm # 3494 .

cjerdonek
источник
19
Это работает очень хорошо. Вы также можете сделать что-то подобное, node ./script.js server ${PORT:-8080}чтобы сделать это необязательным.
выпускной
7
Кажется, я не могу сделать это в Windows с Git Bash. Кто-нибудь получил это работает, может быть? (та же самая команда работает на Ubuntu)
Каролис Шарапницкис
3
Эй, @graup это сработало для меня NODE_PORT=${PORT=8080}(примерно так же), но не: - синтаксис
MaieonBrix
14
Это не работает кросс-платформенный! Например, в Windows команда должна быть node ./script.js server %PORT%. Рассмотрите возможность использования cross-var и cross-env .
Стейн де Витт
Вариант использования env vars в качестве cli args мне кажется довольно ограниченным? Также можно использовать что-то вроде модуля конфигурации для обработки переменных env, значений по умолчанию и конфигурации в целом.
Mr5o1
93

Вы также можете сделать это:

В package.json:

"scripts": {
    "cool": "./cool.js"
}

В cool.js:

 console.log({ myVar: process.env.npm_config_myVar });

В CLI:

npm --myVar=something run-script cool

Должен вывести:

{ myVar: 'something' }

Обновление: Используя npm 3.10.3, кажется, что это строчные буквы process.env.npm_config_переменных? Я также использую better-npm-run, так что я не уверен , если это ваниль поведение по умолчанию или нет, но этот ответ будет работать. Вместоprocess.env.npm_config_myVar , чтобы попробоватьprocess.env.npm_config_myvar

francoisrv
источник
4
Спасибо, это сработало для меня! Чего мне не хватало, так это префикса npm_config_ к имени переменной, которую вы указываете в командной строке.
jp093121
2
Это не верно. process.env.npm_config_myVarвозвращает истину, а не значение.
Карл Моррисон
1
Работает с версией npm 6.8.0, но только когда я использовал строчные буквы для имени переменной. это выглядит так: измените его на строчные.
Ofir
Отличное решение, работает со строчными параметрами на npm 6.5.0
GavinBelson
78

jakub.g ответ правильный, однако пример с использованием grunt кажется немного сложным.

Итак, мой более простой ответ:

- Отправка аргумента командной строки в скрипт npm

Синтаксис для отправки аргументов командной строки в скрипт npm:

npm run [command] [-- <args>]

Представьте, что в нашем package.json есть задача запуска npm, чтобы запустить сервер разработки webpack:

"scripts": {
  "start": "webpack-dev-server --port 5000"
},

Мы запускаем это из командной строки с npm start

Теперь, если мы хотим передать порт в скрипт npm:

"scripts": {
  "start": "webpack-dev-server --port process.env.port || 8080"
},

запуск этого и передача порта, например 5000 через командную строку, будет выглядеть следующим образом:

npm start --port:5000

- Использование config.json config:

Как упомянуто jakub.g , вы можете установить параметры в конфигурации вашего package.json.

"config": {
  "myPort": "5000"
}

"scripts": {
  "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080"
},

npm start будет использовать порт, указанный в вашей конфигурации, или вы можете переопределить его

npm config set myPackage:myPort 3000

- Установка параметров в вашем скрипте npm

Пример чтения набора переменных в вашем скрипте npm. В этом примереNODE_ENV

"scripts": {
  "start:prod": "NODE_ENV=prod node server.js",
  "start:dev": "NODE_ENV=dev node server.js"
},

читать NODE_ENV в server.js либо prod, либо dev

var env = process.env.NODE_ENV || 'prod'

if(env === 'dev'){
    var app = require("./serverDev.js");
} else {
    var app = require("./serverProd.js");
}
svnm
источник
5
обратите внимание, что синтаксис, такой как "start:prod": "NODE_ENV=prod node server.js"in package.json, не будет работать в Windows, если вы не используете cross-env
jakub.g
2
Исправление ?: "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080" },должно быть в "start": "webpack-dev-server --port $npm_package_config_myPort || 8080" },соответствии с моим использованием, объясненным в этом руководстве . Ссылка на процесс может быть использована в JavaScript, по-видимому.
Аарон Роллер
35

Npm 2.x Поддержка Cli Args

команда

npm run-script start -- --foo=3

Package.json

"start": "node ./index.js"

index.js

console.log('process.argv', process.argv);

Грегори Улье
источник
1
В принятом ответе (приведенном на год раньше, чем этот) уже упоминается этот метод.
Дан Дакалеску
34

Используйте process.argvв своем коде, а затем просто предоставить трейлинг$* в конец значения для ваших скриптов.

В качестве примера попробуйте это с помощью простого скрипта, который просто записывает предоставленные аргументы в стандартный формат echoargs.js:

console.log('arguments: ' + process.argv.slice(2));

package.json:

"scripts": {
    "start": "node echoargs.js $*"
}

Примеры:

> npm start 1 2 3
arguments: 1,2,3

process.argv[0] это исполняемый файл (узел), process.argv[1] это ваш скрипт.

Протестировано с npm v5.3.0 и узлом v8.4.0

Питер
источник
Не работает после добавления --к аргументам, например - npm run demo.js --skip, работает, если добавлен дополнительный --, например -npm run demo.js -- --skip
Shreyas
Можете ли вы использовать этот метод без отдельного echoargs.jsфайла сценария?
Джошуа Пинтер
@JoshuaPinter echoargs.js приведен в качестве примера, я отредактирую свой ответ, чтобы прояснить это
Питер
@ Питер Правильно, но должен ли это быть файл сценария. Я пытаюсь создать сценарий , который использует adbдля толкания.db файла в эмулятор Android и принимает параметр для локального пути .dbфайла, чтобы передать к нему, который является первым параметром adb push. Как-то так: "db:push": "adb push process.argv.slice(2) /data/data/com.cntral.app/databases/database.db"и я хочу позвонить npm run db:push /Users/joshuapinter/Downloads/updated.db. Какие-нибудь мысли?
Джошуа Пинтер
21

Если вы хотите передать аргументы в середину сценария npm, а не просто добавлять их в конец, тогда встроенные переменные среды, похоже, будут работать хорошо:

"scripts": {
  "dev": "BABEL_ARGS=-w npm run build && cd lib/server && nodemon index.js",
  "start": "npm run build && node lib/server/index.js",
  "build": "mkdir -p lib && babel $BABEL_ARGS -s inline --stage 0 src -d lib",
},

Здесь npm run devпередает -wфлаг наблюдения babel, но один npm run startраз запускает обычную сборку.

Дэн Росс
источник
Как это называется из CLI?
Bwobst
@dresdin npm run dev,npm start
TJ
2
Нужно использовать cross-env, чтобы использовать его в Windows.
Fracz
8

Я использовал эту однострочную версию в прошлом, и через некоторое время вдали от Node.js пришлось недавно попытаться открыть ее заново. Подобно решению, упомянутому @francoisrv, он используетnode_config_* переменные.

Создайте следующий минимальный package.jsonфайл:

{
  "name": "argument",
  "version": "1.0.0",
  "scripts": {
    "argument": "echo \"The value of --foo is '${npm_config_foo}'\""
  }
}

Запустите следующую команду:

npm run argument --foo=bar

Обратите внимание на следующий вывод:

Значение --foo равно 'bar'

Все это хорошо описано в официальной документации npm:

Примечание . Заголовок « Переменные среды» объясняет, что переменные внутри скриптов ведут себя не так, как определено в документации. Это верно, когда речь идет о чувствительности к регистру , а также о том, задан ли аргумент пробелом или знаком равенства .

Примечание. Если вы используете аргумент с дефисами, они будут заменены подчеркиванием в соответствующей переменной окружения. Например, npm run example --foo-bar=bazбудет соответствовать${npm_config_foo_bar} .

Примечание. Для пользователей Windows, не относящихся к WSL, см. Комментарии @Doctor Blue ниже ... TL; DR заменить ${npm_config_foo}на %npm_config_foo%.

Эндрю Одри
источник
Привет. Я пытаюсь использовать твой пример, но боюсь, что он не работает для меня. Я копировать-вставить ваш «аргумент» сценарий, и сделал то же самое для команды для запуска ( npm run argument --foo=bar), но переменная не заменяется: "The value of --foo is '${npm_config_foo}'". Запуск на Windows 10, если это имеет значение, с версией 6.9.0 NPM.
Доктор Блю
@DoctorBlue Ах да, Node и Windows не всегда хорошо играют ... Эта статья может пролить свет на переменные окружения в сценариях npm: (TL; команды DR идут прямо в хост-ОС, даже если запущены из другой оболочки) блог .risingstack.com / node-js-windows-10-tutorial /… Я не уверен в вашей настройке, но если вы используете Git Bash для запуска Node, вы можете рассмотреть возможность его запуска через документы
Эндрю Одри
1
Я понял. Просто пришлось использовать %npm_config_foo%вместо этого. Чистая командная строка Windows / powershell здесь. (У меня тоже нет выбора.)
Доктор Блю
6

Это на самом деле не отвечает на ваш вопрос, но вы всегда можете вместо этого использовать переменные окружения:

"scripts": {
    "start": "PORT=3000 node server.js"
}

Затем в вашем файле server.js:

var port = process.env.PORT || 3000;
DrunkenBeetle
источник
1
Это хорошо, если вы работаете на платформе Unix. К сожалению, он не работает с Windows, поскольку у него есть собственное соглашение.
Юхо Вепсяляйнен,
6

Большинство приведенных выше ответов касаются простой передачи аргументов в ваш скрипт NodeJS, вызываемый npm. Мое решение для общего пользования.

Просто оберните скрипт npm shвызовом интерпретатора оболочки (например ) и передайте аргументы как обычно. Единственное исключение - первый номер аргумента 0.

Например, вы хотите добавить скрипт npm someprogram --env=<argument_1>, где someprogramпросто печатается значение envаргумента:

package.json

"scripts": {
  "command": "sh -c 'someprogram --env=$0'"
}

Когда вы запустите это:

% npm run -s command my-environment
my-environment
Александр Приезжев
источник
Спасибо! Это было прекрасно!
Фелипе Дезидерати
Просто и элегантно! не будет работать на оболочке MS DOS.
n370
3

Из того, что я вижу, люди используют сценарии package.json, когда они хотели бы запустить сценарий более простым способом. Например, чтобы использовать nodemonтот, который установлен в локальных node_modules, мы не можем вызвать nodemonнапрямую из cli, но мы можем вызвать его с помощью ./node_modules/nodemon/nodemon.js. Итак, чтобы упростить эту долгую печать, мы можем поместить это ...

    ...

    сценарии: {
      'start': 'nodemon app.js'
    }

    ...

... затем вызовите npm startдля использования 'nodemon', у которого app.js является первым аргументом.

То, что я пытаюсь сказать, если вы просто хотите запустить свой сервер с помощью nodeкоманды, я не думаю, что вам нужно использовать scripts. Печатание npm startили node app.jsже усилия.

Но если вы хотите использовать nodemonи хотите передать динамический аргумент, не используйтеscript . Попробуйте вместо этого использовать символическую ссылку.

Например, используя миграцию с sequelize. Я создаю символическую ссылку ...

ln -s node_modules/sequelize/bin/sequelize sequelize

... И я могу передать любой аргумент, когда я называю это ...

./sequlize -h /* show help */

./sequelize -m /* upgrade migration */

./sequelize -m -u /* downgrade migration */

так далее...

На данный момент, использование символической ссылки - лучший способ, который я мог понять, но я не думаю, что это лучшая практика.

Я также надеюсь на ваше мнение на мой ответ.

Kiddo
источник
1
Это не отвечает на вопрос вообще. Я не знаю, как это получило 6 голосов, но поздравляю :)
Дэн Даскалеску
2

Примечание: этот подход изменяет вашpackage.json на лету, используйте его, если у вас нет альтернативы.

Мне пришлось передать аргументы командной строки в мои сценарии, которые были что-то вроде:

"scripts": {
    "start": "npm run build && npm run watch",
    "watch": "concurrently  \"npm run watch-ts\" \"npm run watch-node\"",
    ...
}

Итак, это означает, что я запускаю свое приложение с npm run start.

Теперь, если я хочу передать некоторые аргументы, я бы начал с:

npm run start -- --config=someConfig

Что это делает: npm run build && npm run watch -- --config=someConfig. Проблема в том, что он всегда добавляет аргументы в конец скрипта. Это означает, что все цепочечные сценарии не получают эти аргументы (аргументы могут быть или не быть обязательными для всех, но это другая история). Кроме того, при вызове связанных сценариев эти сценарии не будут получать переданные аргументы. то естьwatch скрипт не получит переданные аргументы.

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

Я не мог найти какой-либо правильный способ достичь этого, поэтому я попробовал именно это.

Я создал файл javascript: start-script.jsна родительском уровне приложения у меня есть «default.package.json», и вместо того, чтобы поддерживать «package.json», я поддерживаю «default.package.json». Цель start-script.jsonсостоит в том, чтобы прочитать default.package.json, извлечь scriptsи найти и npm run scriptnameзатем добавить переданные аргументы к этим сценариям. После этого он создаст новый package.jsonи скопирует данные из default.package.json с измененными сценариями, а затем вызовет npm run start.

const fs = require('fs');
const { spawn } = require('child_process');

// open default.package.json
const defaultPackage = fs.readFileSync('./default.package.json');
try {
    const packageOb = JSON.parse(defaultPackage);
    // loop over the scripts present in this object, edit them with flags
    if ('scripts' in packageOb && process.argv.length > 2) {

        const passedFlags = ` -- ${process.argv.slice(2).join(' ')}`;
        // assuming the script names have words, : or -, modify the regex if required.
        const regexPattern = /(npm run [\w:-]*)/g;
        const scriptsWithFlags = Object.entries(packageOb.scripts).reduce((acc, [key, value]) => {
            const patternMatches = value.match(regexPattern);
            // loop over all the matched strings and attach the desired flags.
            if (patternMatches) {
                for (let eachMatchedPattern of patternMatches) {
                    const startIndex = value.indexOf(eachMatchedPattern);
                    const endIndex = startIndex + eachMatchedPattern.length;
                    // save the string which doen't fall in this matched pattern range.
                    value = value.slice(0, startIndex) + eachMatchedPattern + passedFlags + value.slice(endIndex);
                }
            }
            acc[key] = value;
            return acc;
        }, {});
        packageOb.scripts = scriptsWithFlags;
    }

    const modifiedJSON = JSON.stringify(packageOb, null, 4);
    fs.writeFileSync('./package.json', modifiedJSON);

    // now run your npm start script
    let cmd = 'npm';
    // check if this works in your OS
    if (process.platform === 'win32') {
        cmd = 'npm.cmd';    // https://github.com/nodejs/node/issues/3675
    }
    spawn(cmd, ['run', 'start'], { stdio: 'inherit' });

} catch(e) {
    console.log('Error while parsing default.package.json', e);
}

Теперь вместо того, чтобы делать npm run start, я делаюnode start-script.js --c=somethis --r=somethingElse

Начальный прогон выглядит хорошо, но не был тщательно протестирован. Используйте его, если вам нравится разработка приложений.

Ашиш Ранджан
источник
1

Я нашел этот вопрос, когда пытался решить свою проблему с помощью команды sequelize seed: generate cli:

node_modules/.bin/sequelize seed:generate --name=user

Позвольте мне перейти к сути. Я хотел бы иметь короткую команду сценария в моем package.json файл и одновременно предоставить аргумент --name

Ответ пришел после нескольких экспериментов. Вот моя команда в package.json

"scripts: {
  "seed:generate":"NODE_ENV=development node_modules/.bin/sequelize seed:generate"
}

... и вот пример запуска его в терминале для генерации начального файла для пользователя

> yarn seed:generate --name=user

> npm run seed:generate -- --name=user

FYI

yarn -v
1.6.0

npm -v
5.6.0
Серж Селецкий
источник
2
Это тот же метод, который объясняется в принятом ответе еще в 2013 году, чтобы пройти -- --arg1, ...?
Дан Дакалеску
2
ОК, тогда зачем повторять ответ?
Дан Даскалеску
Я поделился ярким примером использования, не правда ли?
Серж Селецкий
2
Если бы я хотел поделиться другим примером для техники, уже описанной в другом ответе, я бы добавил свой пример в качестве комментария к этому ответу.
Дан Даскалеску
1
Гоча, так будет в следующий раз
Сергей Селецкий,
0

npm run script_target - <аргумент> По сути, это способ передачи аргументов командной строки, но он будет работать только в том случае, если в скрипте запущена только одна команда, например, я запускаю команду, т.е. npm run start - 4200

"script":{
       "start" : "ng serve --port="
 }

Это будет выполняться для передачи параметров командной строки, но что если мы запустим более одной команды вместе, например, npm, запустите build c: / workspace / file

"script":{
       "build" : "copy c:/file <arg> && ng build"
 } 

но он будет интерпретировать как это при выполнении copy c: / file && ng build c: / work space / file, и мы ожидаем что-то вроде этого копии c: / file c: / work space / file && ng build

Примечание: - поэтому параметр командной строки работает только в том случае, если в сценарии только одна команда.

Я прочитал некоторые ответы выше, в которых некоторые из них пишут, что вы можете получить доступ к параметру командной строки, используя символ $, но это не сработает

Солнечный Гоэль
источник
0

Я знаю, что уже есть утвержденный ответ, но мне нравится этот подход JSON.

npm start '{"PROJECT_NAME_STR":"my amazing stuff", "CRAZY_ARR":[0,7,"hungry"], "MAGICAL_NUMBER_INT": 42, "THING_BOO":true}';

Обычно у меня есть 1 вариант, такой как имя проекта, поэтому я нахожу это быстрым и простым.

Также у меня часто есть что-то подобное в моем package.json

"scripts": {
    "start": "NODE_ENV=development node local.js"
}

И, будучи жадным, я хочу "все это", NODE_ENV и линейку CMD.

Вы просто получаете доступ к таким вещам в своем файле (в моем случае local.js)

console.log(process.env.NODE_ENV, starter_obj.CRAZY_ARR, starter_obj.PROJECT_NAME_STR, starter_obj.MAGICAL_NUMBER_INT, starter_obj.THING_BOO);

Вам просто нужно, чтобы этот бит был выше (я использую версию 10.16.0)

var starter_obj = JSON.parse(JSON.parse(process.env.npm_config_argv).remain[0]);

Anyhoo, вопрос уже ответил. Мысль, которой я поделюсь, поскольку я использую этот метод много.

fullstacklife
источник