Надсилання аргументів командного рядка до сценарію npm


818

scriptsЧастина мого в package.jsonданий час виглядає наступним чином :

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

... це означає, що я можу запустити, npm startщоб запустити сервер. Все йде нормально.

Однак я хотів би мати можливість запустити щось на зразок npm start 8080і передати аргументи (аргументи) script.js(наприклад, npm start 8080=> node ./script.js server 8080). Чи можливо це?

Відповіді:


1130

Редагувати 2014.10.30: Аргументи можна передавати npm runстаном на npm 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 або minimalist ; nodejs відкриває process.argvглобально, що містить значення параметрів командного рядка, але це API низького рівня (масив рядків, розділених пробілом, як це передбачено операційною системою для виконання вузла).


Редагувати 2013.10.03: Наразі це неможливо безпосередньо. Але є відповідна проблема GitHub, відкритаnpm для впровадження поведінки, про яку ви просите. Здається, консенсус полягає в тому, щоб це було здійснено, але це залежить від іншого питання, яке вирішувалося раніше.


Оригінальна відповідь: Як якесь вирішення (хоча і не дуже зручне), ви можете зробити наступне:

Скажіть назву вашого пакета від package.jsonє, 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).


1
Це також чудово працює разом з такими пакетами yargs; всі параметри після --кані можна ідеально проаналізувати у вашому сценарії.
Томас

11
AFAIKS, це дозволяє лише додавати параметри до кінця сценаріїв. Що робити, якщо вам потрібні параметри посередині?
Спок

108
-- --argsсвяте дерьмо , що це дивно , але добре
Август

9
@Spock Ви можете використовувати функції оболонки. Ось настройка eslint + tslint, яку я використовую, щоб дозволити передачу користувальницьких аргументів eslint, for insance, через "npm run lint - -f unix": "lint": "f () {eslint -f codeframe $ @. && npm run tslint && echo 'lint clean!';}; f "
еманаут

3
Приємніший спосіб встановити значення "myPackage: myPort 9090" - це прапор конфігурації для команди "--myPackage: myPort = 9090" - keithcirkel.co.uk/how-to-use-npm-as-a-build -tool
chrismarx

222

Ви попросили мати можливість запускати щось на кшталт npm start 8080 . Це можливо без необхідності змінювати script.jsабо конфігурувати файли наступним чином.

Наприклад, у "scripts"значення JSON включіть:

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

А потім з командного рядка:

$ PORT=8080 npm start

Я підтвердив, що це працює за допомогою bash та npm 1.4.23. Зауважте, що ця обхідна проблема не потребує вирішення номінальної проблеми GitHub № 3494 .


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 здається мені досить обмеженим? Може також використовувати щось на зразок конфігураційного модуля для обробки env vars, default і конфігурації загалом.
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


4
Дякую, це працювало для мене! Чого я бракував, префікс "npm_config_" до імені змінної, який ви вказуєте в командному рядку.
jp093121

2
Це неправильно. process.env.npm_config_myVarповертає істинне, а не значення.
Карл Моррісон

1
Працює з npm версією 6.8.0, але лише тоді, коли я використовував малі літери для назви змінної. схоже, що llke npm змінити його на малі
Ofir

Чудове рішення, працює з нижньою літерою на npm 6.5.0
GavinBelson

77

Відповідь jakub.g правильна, проте приклад використання грунту здається трохи складним.

Тож моя простіша відповідь:

- Відправлення аргументу командного рядка до сценарію npm

Синтаксис для надсилання аргументів командного рядка до сценарію npm:

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

Уявіть, що в нашому пакеті.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 , ви можете альтернативно встановити параметри в конфігурації пакета.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");
}

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.
Аарон Ролик


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
Шрейяс

Чи можете ви використовувати цей метод, не маючи окремого echoargs.jsфайлу сценарію?
Джошуа Пінтер

@JoshuaPinter echoargs.js мається на увазі як приклад, я відредагую свою відповідь, щоб зробити це зрозумілим
Пітер

@Peter Правильно, але чи повинен це бути файл сценарію. Я намагаюся створити скрипт, який використовує 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прапор годинника для маркування, але він npm run startпросто виконує звичайну збірку один раз.


Як це називається від CLI?
bwobst

@dresdin npm run dev,npm start
TJ

2
Щоб використовувати його в 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 - "бар"

Все це добре зафіксовано в офіційній документації npm:

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

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

Примітка. Для користувачів, що не належать до WSL Windows, дивіться коментарі @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 Ага, вузол та Windows не завжди грають добре ... Ця стаття може пролити трохи змінних змін у середовищі в сценаріях npm: (TL; команди DR переходять безпосередньо до хост-операційної системи, навіть якщо запускається з іншої оболонки) блог .risingstack.com / node-js-windows-10-tutorial /… Я не впевнений у своєму налаштуванні, але якщо ви використовуєте Git Bash для запуску Node, ви можете розглянути можливість запуску його через документи
Андрій Одрі

1
Я зрозумів це. Просто довелося використовувати %npm_config_foo%замість цього. Тут чистий командний рядок / повноваження Windows. (Немає вибору і у вас.)
Доктор Блю

6

Це насправді не відповідає на ваше запитання, але ви завжди можете використовувати змінні середовища:

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

Потім у вашому файлі server.js:

var port = process.env.PORT || 3000;

1
Це добре, якщо ви перебуваєте на платформі Unix. На жаль, він не працює з Windows, оскільки це має власну конвенцію.
Juho Vepsäläinen

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 */

тощо ...

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

Я також сподіваюся на вашу думку на мою відповідь.


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: create cli command:

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
gotcha, зробимо так наступного разу
Серж Селецький

0

npm run script_target - <argument> В основному це спосіб передачі аргументів командного рядка, але він буде працювати лише в тому випадку, коли сценарій має лише одну команду, як я виконую команду, тобто npm start start - 4200

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

Це буде працювати для передачі параметрів командного рядка, але що робити, якщо ми запускаємо більше однієї команди разом, як npm run build c: / workpace / file

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

але він буде інтерпретувати так, як виконує копію c: / file && ng build c: / робочий простір / файл, і нас очікує щось подібне до цієї копії c: / file c: / робочий простір / 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 вар, який мені потрібен, наприклад, назва проекту, тому я вважаю цей швидкий «простим».

Також у мене часто є щось подібне у своєму пакеті.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);

Вам просто потрібно мати цей біт над ним (я працюю v10.16.0 btw)

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

Anyhoo, на питання вже відповів. Думав, я поділюсь, оскільки я багато використовую цей метод.

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