Enviando argumentos da linha de comando para o script npm

819

A scriptsparte do meu package.jsonatualmente é assim:

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

... o que significa que posso executar npm startpara iniciar o servidor. Por enquanto, tudo bem.

No entanto, eu gostaria de poder executar algo como npm start 8080e ter o argumento (s) passado script.js(por exemplo npm start 8080=> node ./script.js server 8080). Isso é possível?

arnemart
fonte

Respostas:

1132

Editar 2014.10.30: É possível passar argumentos para a npm runpartir do npm 2.0.0

A sintaxe é a seguinte:

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

Observe o necessário --. É necessário separar os parâmetros passados ​​para se npmcomandar e os parâmetros passados ​​para o seu script.

Então, se você tem package.json

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

Em seguida, os seguintes comandos seriam equivalentes:

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

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

Para obter o valor do parâmetro, consulte esta pergunta . Para ler parâmetros nomeados, provavelmente é melhor usar uma biblioteca de análise como yargs ou minimist ; O nodejs expõe process.argvglobalmente, contendo valores de parâmetros da linha de comandos, mas essa é uma API de baixo nível (matriz de cadeias separada por espaço em branco, conforme fornecido pelo sistema operacional ao executável do nó).


Editar 2013.10.03: atualmente não é possível diretamente. Mas há um problemanpm relacionado ao GitHub aberto para implementar o comportamento que você está solicitando. Parece que o consenso é que isso seja implementado, mas isso depende de outro problema que foi resolvido antes.


Resposta original: Como uma solução alternativa (embora não muito útil), você pode fazer o seguinte:

Diga o nome do seu pacote de package.jsonis myPackagee você também

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

Em seguida, adicione package.json:

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

E no seu 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

Dessa forma, por padrão npm start, usará 8080. No entanto, você pode configurá-lo (o valor será armazenado npmem seu armazenamento interno):

npm config set myPackage:myPort 9090

Em seguida, ao chamar npm start, 9090 será usado (o padrão de package.jsonserá substituído).

jakub.g
fonte
1
Isso também funciona perfeitamente junto com pacotes como yargs; todos os parâmetros após o --podem ser analisados ​​perfeitamente em seu script.
Thomas
11
AFAIKS, isso só permite adicionar parâmetros ao final de seus scripts. E se você precisar de parâmetros no meio?
Spock
109
-- --argsporcaria santa que é estranho, mas tudo bem #
24417
9
@ Spock Você pode usar funções de shell. Aqui está uma configuração eslint + tslint que eu uso para permitir a passagem de argumentos personalizados para eslint, por exemplo, através de "npm run lint - -f unix": "lint": "f () {eslint -f codeframe $ @. && npm run tslint && echo 'lint clean!';}; f "
ecmanaut 25/09/17
3
A melhor maneira de definir o valor "myPackage: myPort 9090" é com um sinalizador de configuração com o comando "--myPackage: myPort = 9090" - keithcirkel.co.uk/how-to-use-npm-as-a-build -tool
chrismarx
223

Você pediu para poder executar algo parecido npm start 8080 . Isso é possível sem a necessidade de modificar script.jsou configurar os arquivos da seguinte maneira.

Por exemplo, no seu "scripts"valor JSON, inclua--

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

E então a partir da linha de comando:

$ PORT=8080 npm start

Eu confirmei que isso funciona usando o bash e o npm 1.4.23. Observe que esta solução alternativa não exige que o problema npm 3494 do GitHub seja resolvido.

cjerdonek
fonte
19
Isso funciona muito bem. Você também pode fazer algo como node ./script.js server ${PORT:-8080}torná-lo opcional.
graup
7
Parece que não consigo fazer isso no Windows com o git bash. Alguém conseguiu funcionar, talvez? (o mesmo comando funciona no ubuntu)
Karolis Šarapnickis 06/10
3
Hey @graup isso funcionou para mim NODE_PORT=${PORT=8080}(notive a igual), mas não o: - sintaxe
MaieonBrix
14
Isso não funciona em várias plataformas! Por exemplo, no Windows, o comando precisaria ser node ./script.js server %PORT%. Considere usar cross-var e cross-env .
Stijn de Witt
A maneira de usar o env vars como cli args parece bastante limitada para mim? Também pode usar algo como o módulo de configuração para lidar com env vars, padrões e configuração em geral.
Mr5o1
93

Você também pode fazer isso:

Em package.json:

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

Em cool.js:

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

Na CLI:

npm --myVar=something run-script cool

Saída deve:

{ myVar: 'something' }

Atualização: Usando o npm 3.10.3, parece que ele apresenta minúsculas as process.env.npm_config_variáveis? Também estou usando better-npm-run, por isso não tenho certeza se esse é o comportamento padrão da baunilha ou não, mas esta resposta está funcionando. Em vez de process.env.npm_config_myVar, tenteprocess.env.npm_config_myvar

francoisrv
fonte
4
Graças isso funcionou para mim! O que eu estava perdendo especificamente o prefixo "npm_config_" para o nome da variável que você está especificando na linha de comando.
Jsp093121
2
Isto está errado. process.env.npm_config_myVarretorna verdadeiro, não o valor.
Karl Morrison
1
Funciona com o npm versão 6.8.0, mas apenas quando usei letras minúsculas para o nome da variável. parece mudança npm lilke-lo para minúsculas
Ofir Meguri
Ótima solução, funciona com o parâmetro minúsculo no npm 6.5.0
GavinBelson
78

A resposta de jakub.g está correta, no entanto, um exemplo usando o grunhido parece um pouco complexo.

Então, minha resposta mais simples:

- Enviando um argumento de linha de comando para um script npm

Sintaxe para enviar argumentos de linha de comando para um script npm:

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

Imagine que temos uma tarefa de inicialização do npm em nosso package.json para iniciar o servidor de desenvolvimento webpack:

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

Executamos isso a partir da linha de comando com npm start

Agora, se queremos passar uma porta para o script npm:

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

executando isso e passando a porta, por exemplo, 5000 via linha de comando, seria o seguinte:

npm start --port:5000

- Usando a configuração package.json:

Como mencionado no jakub.g , você pode definir parâmetros na configuração do seu package.json

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

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

npm start usará a porta especificada em sua configuração ou, em alternativa, você pode substituí-la

npm config set myPackage:myPort 3000

- Definindo um parâmetro no seu script npm

Um exemplo de leitura de uma variável definida no seu script npm. Neste exemploNODE_ENV

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

leia NODE_ENV em server.js quer prod ou dev

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

if(env === 'dev'){
    var app = require("./serverDev.js");
} else {
    var app = require("./serverProd.js");
}
svnm
fonte
5
note que sintaxe como "start:prod": "NODE_ENV=prod node server.js"em package.jsonnão funcionará no Windows, a menos que você use cross-env
jakub.g
2
Correção ?: "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080" },deve estar de "start": "webpack-dev-server --port $npm_package_config_myPort || 8080" },acordo com o meu uso explicado neste tutorial . O processo ref pode ser usado dentro do javascript aparentemente.
Aaron Rolo
35

npm 2.x cli args de suporte

Comando

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

Package.json

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

Index.js

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

Gregory Houllier
fonte
1
A resposta aceita (dada um ano antes desta) já menciona essa técnica.
Dan Dascalescu 14/10/19
34

Use process.argvno seu código e forneça apenas uma $*entrada para o valor dos scripts.

Como exemplo, tente com um script simples que apenas registra os argumentos fornecidos para padronizar echoargs.js:

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

package.json:

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

Exemplos:

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

process.argv[0]é o executável (nó), process.argv[1]é o seu script.

Testado com npm v5.3.0 e nó v8.4.0

Pedro
fonte
Não funciona após a adição --de argumentos, por exemplo - npm run demo.js --skip, ele funciona se acrescentou um extra --, por exemplo -npm run demo.js -- --skip
Shreyas
Você pode usar esse método sem ter um echoargs.jsarquivo de script separado ?
Joshua Pinter
@JoshuaPinter echoargs.js é apenas significou como exemplo, eu vou editar a minha resposta para deixar isso claro
Peter
@ Peter Certo, mas precisa ser um arquivo de script. Estou tentando criar um script que usa adbpara enviar um .dbarquivo para o emulador do Android e aceita um parâmetro para o caminho local do .dbarquivo para enviar para ele, que é o primeiro parâmetro de adb push. Algo assim: "db:push": "adb push process.argv.slice(2) /data/data/com.cntral.app/databases/database.db"e eu quero chamá-lo com npm run db:push /Users/joshuapinter/Downloads/updated.db. Alguma ideia?
Joshua Pinter
21

Se você deseja passar argumentos para o meio de um script npm, em vez de apenas anexá-los ao final, as variáveis ​​de ambiente embutidas parecem funcionar bem:

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

Aqui, npm run devpassa a -wbandeira de observação para babel, mas npm run startapenas executa uma compilação regular uma vez.

Dan Ross
fonte
Como isso é chamado a partir da CLI?
bwobst
@dresdin npm run dev,npm start
TJ
2
Precisa usar o ambiente cruzado para usá-lo no Windows.
Fracz 17/10/16
8

Eu estava usando essa linha única no passado e, depois de um tempo longe do Node.js, tentei redescobri-la recentemente. Semelhante à solução mencionada por @francoisrv, utiliza as node_config_*variáveis.

Crie o seguinte package.jsonarquivo mínimo :

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

Execute o seguinte comando:

npm run argument --foo=bar

Observe a seguinte saída:

O valor de --foo é 'bar'

Tudo isso está bem documentado na documentação oficial do npm:

Nota: O cabeçalho Variáveis ​​de ambiente explica que as variáveis ​​contidas nos scripts se comportam de maneira diferente do que está definido na documentação. Isso é verdade quando se trata de distinção entre maiúsculas e minúsculas e também se o argumento é definido com um sinal de espaço ou igual .

Nota: Se você estiver usando um argumento com hífens, eles serão substituídos por sublinhados na variável de ambiente correspondente. Por exemplo, npm run example --foo-bar=bazcorresponderia a ${npm_config_foo_bar}.

Nota: Para usuários não Windows do WSL, consulte os comentários do @Doctor Blue abaixo ... TL; DR substitua ${npm_config_foo}por %npm_config_foo%.

Andrew Odri
fonte
Olá. Estou tentando usar o seu exemplo, mas receio que não esteja funcionando para mim. Eu copiar-colar o seu script "argumento", e fez o mesmo para o comando a executar ( npm run argument --foo=bar), mas a variável não é substituído: "The value of --foo is '${npm_config_foo}'". Executando no Windows 10, se isso importa, com a versão 6.9.0 do NPM.
Doctor Blue
@DoctorBlue Ahh direita, Node e Windows nem sempre jogar bonito ... Este artigo pode lançar alguma luz sobre as variáveis de ambiente em scripts do MPN: (TL; DR comandos ir direto para o sistema operacional hospedeiro, mesmo se lançado a partir de outro shell) blogue .risingstack.com / node-js-windows-10-tutorial /… Não tenho certeza da sua configuração, mas se você estiver usando o Git Bash para executar o Node, considere executá-lo nos documentos da
Andrew Odri em 26/03
1
Eu descobri. Só tinha que usar em seu %npm_config_foo%lugar. Linha de comando / PowerShell do Windows puro aqui. (Não tenha escolha também.)
Doctor Blue
6

Isso realmente não responde à sua pergunta, mas você sempre pode usar variáveis ​​de ambiente:

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

Em seguida, no seu arquivo server.js:

var port = process.env.PORT || 3000;
BêbadoBesouro
fonte
1
Isso é bom desde que você esteja em uma plataforma Unix. Infelizmente, ele não funciona com o Windows, pois possui uma convenção própria.
Juho Vepsäläinen 9/08/2015
6

A maioria das respostas acima cobre apenas passar os argumentos para o script do NodeJS, chamado por npm. Minha solução é para uso geral.

Apenas envolva o script npm com uma shchamada de interpretador de shell (por exemplo ) e passe os argumentos como de costume. A única exceção é que o primeiro número do argumento é 0.

Por exemplo, você deseja adicionar o script npm someprogram --env=<argument_1>, onde someprogramapenas imprime o valor do envargumento:

package.json

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

Quando você o executa:

% npm run -s command my-environment
my-environment
Alexandr Priezzhev
fonte
Obrigado! Isso foi perfeito!
Felipe Desiderati
Simples e elegante! não funcionará em um shell do MS DOS.
n370 19/03
3

Pelo que vejo, as pessoas usam scripts package.json quando desejam executar o script de maneira mais simples. Por exemplo, para usar nodemono instalado no node_modules local, não podemos chamar nodemondiretamente do cli, mas podemos chamá-lo usando ./node_modules/nodemon/nodemon.js. Então, para simplificar essa digitação longa, podemos colocar isso ...

    ...

    scripts: {
      'start': 'nodemon app.js'
    }

    ...

... então chame npm startpara usar 'nodemon', que tem app.js como o primeiro argumento.

O que estou tentando dizer, se você apenas deseja iniciar seu servidor com o nodecomando, acho que não precisa usá-lo scripts. Digitando npm startou node app.jstem o mesmo esforço.

Mas se você deseja usar nodemone deseja passar um argumento dinâmico, também não use script. Tente usar o link simbólico.

Por exemplo, usando a migração com sequelize. Eu crio um link simbólico ...

ln -s node_modules/sequelize/bin/sequelize sequelize

... E eu posso aprovar qualquer discussão quando eu chamo ...

./sequlize -h /* show help */

./sequelize -m /* upgrade migration */

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

etc ...

Nesse ponto, usar o link simbólico é a melhor maneira de descobrir, mas realmente não acho que seja a melhor prática.

Também espero a sua opinião para a minha resposta.

Kiddo
fonte
1
Isso não responde à pergunta. Eu não sei como ele chegou 6 upvotes, mas parabéns :)
Dan Dascalescu
2

Nota: Essa abordagem modifica o seu package.jsonem tempo real, use-o se você não tiver alternativa.

Eu tive que passar argumentos de linha de comando para meus scripts, que eram algo como:

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

Então, isso significa que inicio meu aplicativo npm run start.

Agora, se eu quiser passar alguns argumentos, começaria talvez:

npm run start -- --config=someConfig

O que isto faz é: npm run build && npm run watch -- --config=someConfig. O problema é que ele sempre anexa os argumentos ao final do script. Isso significa que todos os scripts encadeados não recebem esses argumentos (Args pode ou não ser exigido por todos, mas isso é uma história diferente). Além disso, quando os scripts vinculados são chamados, esses scripts não receberão os argumentos passados. ou seja, o watchscript não receberá os argumentos passados.

O uso de produção do meu aplicativo é como um .exe, portanto, passar os argumentos no exe funciona bem, mas se você quiser fazer isso durante o desenvolvimento, fica problemático.

Não consegui encontrar uma maneira adequada de conseguir isso, então é isso que tentei.

Criei um arquivo javascript: start-script.jsno nível pai do aplicativo, tenho um "default.package.json" e, em vez de manter "package.json", mantenho "default.package.json". O objetivo de start-script.jsoné ler default.package.json, extrair scriptse procurar npm run scriptnamee anexar os argumentos passados ​​a esses scripts. Depois disso, ele criará um novo package.jsone copiará os dados de default.package.json com scripts modificados e depois chamará 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);
}

Agora, em vez de fazer npm run start, eu façonode start-script.js --c=somethis --r=somethingElse

A execução inicial parece boa, mas não foi testada completamente. Use-o, se quiser, para o desenvolvimento de aplicativos.

Ashish Ranjan
fonte
1

Eu encontrei essa pergunta enquanto tentava resolver meu problema com o comando sequelize seed: generate cli:

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

Deixe-me ir direto ao ponto. Eu queria ter um comando de script curto no meu arquivo package.json e fornecer o argumento --name ao mesmo tempo

A resposta veio após algumas experiências. Aqui está o meu comando no package.json

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

... e aqui está um exemplo de executá-lo no terminal para gerar um arquivo inicial para um usuário

> yarn seed:generate --name=user

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

Para sua informação

yarn -v
1.6.0

npm -v
5.6.0
Serge Seletskyy
fonte
2
É a mesma técnica que foi explicada na resposta aceita em 2013, para ser aprovada -- --arg1, ...?
Dan Dascalescu 14/10/19
2
OK, então por que repetir a resposta?
Dan Dascalescu 24/10/19
Compartilhei um exemplo distinto de uso, não é óbvio?
Serge Seletskyy 25/10/19
2
Se eu quisesse compartilhar outro exemplo de uma técnica já explicada em uma resposta diferente, adicionaria meu exemplo como um comentário a essa resposta.
Dan Dascalescu 28/10/19
1
entendi, fará dessa maneira da próxima vez
Serge Seletskyy 14/11/19
0

npm executa script_target - <argumento> Basicamente, esta é a maneira de passar os argumentos da linha de comando, mas funcionará apenas no caso em que o script tenha apenas um comando em execução, como eu estou executando um comando, ou seja, npm run start - 4200

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

Isso funcionará para passar parâmetros de linha de comando, mas e se executarmos mais de um comando juntos, como npm run build c: / workspace / file

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

mas interpretará assim enquanto estiver executando cópia c: / file && ng build c: / espaço de trabalho / arquivo e espera-se que algo parecido com esta cópia c: / arquivo c: / espaço de trabalho / arquivo && ng build

Nota: - portanto, o parâmetro da linha de comando funciona apenas com o anúncio esperado no caso de apenas um comando em um script.

Eu li algumas respostas acima, nas quais alguns deles estão escrevendo que você pode acessar o parâmetro da linha de comando usando o símbolo $, mas isso não vai funcionar

Sunny Goel
fonte
0

Eu sei que já existe uma resposta aprovada, mas meio que gosto dessa abordagem JSON.

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

Normalmente, tenho 1 var de que preciso, como o nome de um projeto, então acho isso rápido e simples.

Também frequentemente tenho algo parecido com isto no meu package.json

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

E sendo ganancioso, quero "tudo", NODE_ENV e a linha CMD arg.

Você simplesmente acessa essas coisas no seu arquivo (no meu caso, 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);

Você só precisa ter esse bit acima dele (estou executando a v10.16.0 btw)

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

Anyhoo, pergunta já respondida. Pensei em compartilhar, pois uso muito esse método.

vida cheia
fonte