Передайте аргументы командной строки скриптам npm в package.json

#node.js #npm

#npm #package.json #npm-скрипты

Вопрос:

У меня есть приведенные ниже скрипты в моем package.json:

 "scripts": {
    "vumper": "node node_modules/vumper/index.js",
    "format": "prettier --single-quote -width=80 --write package.json"
 },
  

Пакет ‘vumper’ принимает аргумент командной строки (например, ‘dv’). Что я хотел бы иметь возможность сделать, так это иметь команду, которая запускает оба из них последовательно.

По сути, я хотел бы иметь возможность запускать:

 npm run vumber dv
  

и затем

 npm run format
  

но в одной команде что-то вроде

 npm run my-build dv
  

которые выполнили бы обе вышеуказанные команды, правильно приняв аргумент командной строки ‘dv’ и передав его первому исполнителю npm, выполняющему vumper. Возможно ли это?

Ответ №1:

Короткий ответ:

По сути, то, что вы хотите, — это иметь npm-скрипт примерно такого типа, в котором <arg-here> предоставляется через CLI;

 ...
"scripts": {
  "my-build": "npm run vumper <arg-here> amp;amp; npm run format",
  ...
},
...
  

Однако, к сожалению, npm не имеет встроенной функции для достижения этого.

Специальная опция npm -- (дополнительную информацию об этой опции см. в конце решения 1 ниже) может использоваться только для передачи аргумента в КОНЕЦ скрипта, но НЕ в СЕРЕДИНУ. Итак, если бы ваши две команды были в противоположном порядке, -- параметр можно было бы использовать следующим образом:

 ...
"scripts": {
  "my-build": "npm run format amp;amp; npm run vumper --",
  ...
},
...
  

Чтобы преодолеть ограничение, заключающееся в отсутствии встроенной функции для передачи аргумента в СЕРЕДИНУ скрипта, рассмотрите следующие решения:

  1. Решение, доступное только для Bash, см. в разделе «Решение 1».

  2. Если требуется кроссплатформенная поддержка, следуйте решению, описанному в разделе «Решение 2».


Решение 1 — Bash (macOS / Linux / etc ..):

Настройте свой my-build скрипт в scripts разделе package.json для вызова функции оболочки Bash, как показано ниже:

package.json

 ...
"scripts": {
  "my-build": "func() { npm run vumper "$1" amp;amp; npm run format; }; func",
  "vumper": "node node_modules/vumper/index.js",
  "format": "prettier --single-quote -width=80 --write package.json"
},
...
  

Объяснение:

Функция Bash с именем func выполняет следующее:

  1. Сначала выполняется npm run vumper <arg> . При этом <arg> будет аргументом оболочки, передаваемым через CLI. В скрипте используется ссылка на него $1 (т.Е. первый позиционный параметр / аргумент).
  2. Впоследствии он запускает скрипт с именем format через команду npm run format .

Эти две npm run команды связаны с помощью amp;amp; оператора, поэтому вторая npm run format команда будет выполняться только в том случае, если начальная npm run vumper <arg> команда завершится успешно (т. Е. вернет 0 код выхода).

Запуск my-build скрипта:

Для вызова my-build через ваш CLI вам нужно выполнить:

 npm run my-build -- dv
  

Примечание:

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

  2. Перед аргументом должна быть указана специальная опция -- . В документах этот -- параметр описывается как:

    … Специальная опция -- используется getopt для разграничения конца опций. npm передаст все аргументы после -- непосредственно вашему скрипту: … Аргументы будут переданы только скрипту, указанному после npm run , а не какому-либо сценарию pre или post.


Решение 2 — Кроссплатформенность:

Для кроссплатформенного решения (которое успешно работает с Bash, командной строкой Windows / cmd.exe и PowerShell и т.д.), вам нужно будет использовать вспомогательный скрипт nodejs следующим образом.

run.js

Давайте назовем скрипт nodejs run.js и сохраните их в корневом каталоге проектов на том же уровне, что и package.json.

 const execSync = require('child_process').execSync;

const arg = process.argv[2] || 'dv'; // Default value `dv` if no args provided via CLI.

execSync('npm run vumper '   arg, {stdio:[0, 1, 2]});
execSync('npm run format', {stdio:[0, 1, 2]});
  

package.json

Настройте свой my-build скрипт для вызова run.js следующим образом:

 ...
"scripts": {
  "my-build": "node run",
  "vumper": "node node_modules/vumper/index.js",
  "format": "prettier --single-quote -width=80 --write package.json"
},
...
  

Запуск my-build скрипта:

Согласно решению 1, для вызова my-build через ваш CLI вам необходимо выполнить:

 npm run my-build -- dv
  

Объяснение:

  • run.js используется process.argv для получения аргумента, переданного через CLI (например, dv ). Если при запуске не указано никаких аргументов, npm run my-build в dv npm-скрипт передается значение по умолчанию (т.Е. vumper ).

  • run.js также используется child_process.execSync(...) для выделения / вызова двух npm run команд.

Комментарии:

1.Нет ли пакета cli npm, который просто делал бы что-то вроде const args = process.argv.slice(3); const command = args.reduce( (res, arg, index) => res.replace(new RegExp(`\$${ index 1 }`, 'g'), arg), process.argv[2] ); const execSync = require('child_process').execSync; execSync(command, { stdio: [0, 1, 2] }); ?. Таким образом, я могу просто обернуть любой скрипт с помощью » и добавить к нему такой префикс cli и запустить любой скрипт с упорядоченными аргументами…

Ответ №2:

В Npm теперь есть встроенная опция для передачи аргументов cli непосредственно скриптам. Аргументы cli хранятся в переменных среды с префиксом npm_config_<flagname> , и для них требуется очень строгий синтаксис с формой --<flagname>=<flagvalue> .

Пример:

  "my-build": "npm run vumper %npm_config_myflag% amp;amp; npm run format",
  

В терминале запустите npm run my-build --myflag=my_value для выполнения npm run vumper my_value amp;amp; npm run format .

Примечание:

Чтобы ссылаться на переменную среды в скрипте npm, вы должны использовать синтаксис, зависящий от платформы, т.Е. %npm_config_myflag% в Windows или $npm_config_myflag в Linux.

Обновить:

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

Потенциальный конфликт является очень распространенной проблемой, которая применима во многих контекстах: любое приложение может использовать переменные среды, уже используемые другими приложениями; по этой причине переменные среды обычно имеют префикс имени приложения (например, NVM_HOME, JAVA_HOME). Но этот потенциальный конфликт не является веской причиной избегать использования переменных среды. То же самое, на мой взгляд, относится и к переменным npm params / npm_config env. В документе ничего не говорится о риске конфликтов, подразумевая, что, я полагаю, ими следует управлять как обычно.

Комментарии:

1. Для меня ключевым фактором была специфика платформы. Я пытался $npm_config_myflag работать с Windows и сходил с ума

2. npm также создает свои собственные переменные env с именем npm_config_* для внутренних целей. Обязательно выберите имя для флага / опции (например, --myflag=* ), которое не переопределяет внутренне используемый, поскольку это может привести к нежелательным результатам. Вы можете cd перейти в каталог вашего проекта и запустить npm run env , чтобы получить список переменных env, добавляемых npm. Например. передача --tag=foo не является хорошей идеей, потому что npm добавляет npm_config_tag переменную env (ее значение обычно устанавливается равным latest ). Используя этот метод, неясно, какие внутренние npm_config_* переменные npm могут быть добавлены в будущем, которые вы в конечном итоге можете переопределить.

3. Вы можете обратиться к этому подходу, но использование этого подхода может быть опасным, как объяснил @RobC в комментарии. Таким образом, не в отношении решения этого вопроса, но в целом, если чьим-то требованием является добавление аргумента в конце команды, тогда не используйте подход с переменной среды, в таком случае он / она может использовать npm run <имя_скрипта> — <аргумент>.

Ответ №3:

Мой предпочтительный метод — использование переменных окружения:

 {
  "scripts": {
    "ncc-build": "ncc build $ACTION/src/index.ts -o $ACTION/dist",
    "build:pr-changelog": "ACTION=pr-changelog npm run ncc-build",
  }
}
  

Это должно работать в системах UNIX. Однако я не уверен в совместимости Windows platfrom.

Комментарии:

1. да, это не работает на платформе Windows

2. для Windows вы бы так и сделали set ACTION=... , но если вы хотите использовать на любой платформе, используйте пакет cross-env

Ответ №4:

другой подход для этого — проникнуть очень глубоко в вашу цепочку зависимостей:

раздел скриптов npm:

 "test:local": "cross-env-shell UPDATE_BASELINE=false UPDATE_MODULE=%npm_config_vizdifsingle% run-p koa:ci wdio:local",
"test:remote": "cross-env-shell UPDATE_BASELINE=false  UPDATE_MODULE=%npm_config_vizdifsingle% run-p localtunnel:start koa:ci wdio:remote"
  

используя crossenv и размещение значений npm, вы можете передавать аргументы в env.args

вот так:

 npm run test:local --vizdifsingle=some,value,or,values
  

они будут доступны вам в

 process.env.npm_config_update_module