Envío de argumentos de línea de comandos al script npm

819

La scriptsparte de mi package.jsonactualmente se ve así:

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

... lo que significa que puedo ejecutar npm startpara iniciar el servidor. Hasta aquí todo bien.

Sin embargo, me gustaría poder ejecutar algo como npm start 8080y que los argumentos pasen a script.js(por ejemplo, npm start 8080=> node ./script.js server 8080). es posible?

arnemart
fuente

Respuestas:

1132

Editar 2014.10.30: es posible pasar argumentos a npm runpartir de npm 2.0.0

La sintaxis es la siguiente:

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

Tenga en cuenta lo necesario --. Es necesario separar los parámetros pasados ​​al npmcomando en sí y los parámetros pasados ​​a su script.

Entonces si tienes en package.json

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

Entonces los siguientes comandos serían equivalentes:

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

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

Para obtener el valor del parámetro, vea esta pregunta . Para leer parámetros con nombre, probablemente sea mejor usar una biblioteca de análisis como yargs o minimist ; nodejs expone process.argvglobalmente, conteniendo valores de parámetros de línea de comando, pero esta es una API de bajo nivel (matriz de cadenas separadas por espacios en blanco, según lo proporcionado por el sistema operativo al ejecutable del nodo).


Editar 2013.10.03: Actualmente no es posible directamente. Pero hay un problemanpm relacionado con GitHub abierto para implementar el comportamiento que está solicitando. Parece que el consenso es tener esto implementado, pero depende de que otro problema se resuelva antes.


Respuesta original: como una solución alternativa (aunque no muy útil), puede hacer lo siguiente:

Di el nombre de tu paquete de package.jsones myPackagey también tienes

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

Luego agregue package.json:

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

Y en tu 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

De esa manera, por defecto npm startusará 8080. Sin embargo, puede configurarlo (el valor se almacenará npmen su almacenamiento interno):

npm config set myPackage:myPort 9090

Luego, al invocar npm start, se usará 9090 (el valor predeterminado de package.jsonse anula).

jakub.g
fuente
1
Esto también funciona perfectamente junto con paquetes como yargs; Todos los parámetros posteriores --se pueden analizar perfectamente en su secuencia de comandos.
Thomas
11
AFAIKS, esto solo permite agregar parámetros al final de sus scripts ... ¿qué pasa si necesita parámetros en el medio?
Spock
109
-- --argsSanta mierda que es raro pero está bien
agosto
99
@Spock Puede usar funciones de shell. Aquí hay una configuración de eslint + tslint que uso para permitir pasar argumentos personalizados a eslint, por seguro, a través de "npm run lint - -f unix": "lint": "f () {eslint -f codeframe $ @. && npm run tslint && echo 'lint clean!';}; f "
ecmanaut el
3
La mejor manera de establecer el valor "myPackage: myPort 9090" es con un indicador de configuración para el comando "--myPackage: myPort = 9090" - keithcirkel.co.uk/how-to-use-npm-as-a-build -tool
chrismarx
223

Solicitaste poder ejecutar algo como npm start 8080 . Esto es posible sin necesidad de modificar script.jso configurar los archivos de la siguiente manera.

Por ejemplo, en su "scripts"valor JSON, incluya--

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

Y luego desde la línea de comandos:

$ PORT=8080 npm start

He confirmado que esto funciona con bash y npm 1.4.23. Tenga en cuenta que esta solución alternativa no requiere NPM GitHub edición # 3494 que se resuelva.

cjerdonek
fuente
19
Esto funciona muy bien También puede hacer algo como node ./script.js server ${PORT:-8080}hacerlo opcional.
Graup
77
Parece que no puedo hacer esto en ventanas con git bash. ¿Alguien lo hizo funcionar tal vez? (el mismo comando funciona en ubuntu)
Karolis Šarapnickis
3
Hola @graup, esto funcionó para mí NODE_PORT=${PORT=8080}(noto el igual) pero no el: - sintaxis
MaieonBrix
14
¡Esto no funciona multiplataforma! Por ejemplo, en Windows el comando debería ser node ./script.js server %PORT%. Considere usar cross-var y cross-env .
Stijn de Witt
¿El caso de uso para usar env vars como cli args me parece bastante limitado? También podría usar algo como el módulo de configuración para manejar los valores ambientales, los valores predeterminados y la configuración en general.
Mr5o1
93

También podrías hacer eso:

En package.json:

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

En cool.js:

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

En CLI:

npm --myVar=something run-script cool

Debería dar salida:

{ myVar: 'something' }

Actualización: Usando npm 3.10.3, ¿parece que minúsculas las process.env.npm_config_variables? También estoy usando better-npm-run, así que no estoy seguro de si este es el comportamiento predeterminado de vainilla o no, pero esta respuesta está funcionando. En lugar de process.env.npm_config_myVarintentarprocess.env.npm_config_myvar

francoisrv
fuente
44
Gracias esto funcionó para mí! Lo que me faltaba específicamente el prefijo "npm_config_" al nombre de la variable que está especificando en la línea de comando.
jp093121
2
Esto está mal. process.env.npm_config_myVardevuelve verdadero, no el valor.
Karl Morrison
1
Funciona con npm versión 6.8.0, pero solo cuando utilicé minúsculas para el nombre de la variable. se ve lilke npm cambiarlo a minúsculas
Ofir Meguri
Gran solución, funciona con param en minúsculas en npm 6.5.0
GavinBelson
78

La respuesta de jakub.g es correcta, sin embargo, un ejemplo con grunt parece un poco complejo.

Entonces mi respuesta más simple:

- Enviar un argumento de línea de comando a un script npm

Sintaxis para enviar argumentos de línea de comandos a un script npm:

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

Imagine que tenemos una tarea de inicio npm en nuestro package.json para iniciar el servidor de desarrollo webpack:

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

Ejecutamos esto desde la línea de comando con npm start

Ahora, si queremos pasar un puerto al script npm:

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

ejecutar esto y pasar el puerto, por ejemplo 5000 a través de la línea de comando, sería el siguiente:

npm start --port:5000

- Usando la configuración package.json:

Como lo menciona jakub.g , también puede establecer parámetros en la configuración de su paquete.json

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

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

npm start usará el puerto especificado en su configuración, o alternativamente puede anularlo

npm config set myPackage:myPort 3000

- Establecer un parámetro en su script npm

Un ejemplo de lectura de un conjunto de variables en su script npm. En este ejemploNODE_ENV

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

leer NODE_ENV en server.js ya sea prod o dev

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

if(env === 'dev'){
    var app = require("./serverDev.js");
} else {
    var app = require("./serverProd.js");
}
svnm
fuente
55
tenga en cuenta que la sintaxis como "start:prod": "NODE_ENV=prod node server.js"en package.jsonno funcionará en Windows, a menos que use cross-env
jakub.g
2
¿Corrección ?: "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080" },debe estar de "start": "webpack-dev-server --port $npm_package_config_myPort || 8080" },acuerdo con mi uso explicado en este tutorial . El proceso de referencia puede ser usado dentro del javascript aparentemente.
Aaron Roller
35

npm 2.x admite cli args

Mando

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

Package.json

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

Index.js

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

Gregory Houllier
fuente
1
La respuesta aceptada (dada un año antes que esta) ya menciona esta técnica.
Dan Dascalescu
34

Úselo process.argven su código y luego proporcione un seguimiento $*de la entrada de valor de sus scripts.

Como ejemplo, pruébelo con un script simple que solo registra los argumentos proporcionados para estandarizar echoargs.js:

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

package.json:

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

Ejemplos:

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

process.argv[0]es el ejecutable (nodo), process.argv[1]es tu script.

Probado con npm v5.3.0 y nodo v8.4.0

Peter
fuente
No funciona después de agregar --argumentos, p. Ej. npm run demo.js --skip, Funciona si se agrega un extra --, p. Ej.npm run demo.js -- --skip
Shreyas
¿Puedes usar este método sin tener un echoargs.jsarchivo de script separado ?
Joshua Pinter
@JoshuaPinter echoargs.js es solo un ejemplo, editaré mi respuesta para aclarar esto
Peter
@ Peter Right, pero tiene que ser un archivo de script. Estoy tratando de crear un script que use adbpara enviar un .dbarchivo al emulador de Android y acepte un parámetro para la ruta local del .dbarchivo para enviarlo, que es el primer parámetro de adb push. Algo así: "db:push": "adb push process.argv.slice(2) /data/data/com.cntral.app/databases/database.db"y quiero llamarlo con npm run db:push /Users/joshuapinter/Downloads/updated.db. ¿Alguna idea?
Joshua Pinter el
21

Si desea pasar argumentos al medio de un script npm, en lugar de simplemente agregarlos al final, las variables de entorno en línea parecen funcionar bien:

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

Aquí, npm run devpasa la -wbandera del reloj a babel, pero npm run startsolo ejecuta una compilación normal una vez.

Dan Ross
fuente
¿Cómo se llama esto desde la CLI?
bwobst
@dresdin npm run dev,npm start
TJ
2
Necesita usar cross-env para usarlo en Windows.
fracz
8

Había estado usando este one-liner en el pasado, y después de un tiempo alejado de Node.js tuve que intentar redescubrirlo recientemente. Similar a la solución mencionada por @francoisrv, utiliza las node_config_*variables.

Cree el siguiente package.jsonarchivo mínimo :

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

Ejecute el siguiente comando:

npm run argument --foo=bar

Observe el siguiente resultado:

El valor de --foo es 'bar'

Todo esto está bien documentado en la documentación oficial de npm:

Nota: El encabezado Variables de entorno explica que las variables dentro de los scripts se comportan de manera diferente a lo que se define en la documentación. Esto es cierto cuando se trata de mayúsculas y minúsculas , también si el argumento se define con un espacio o un signo igual .

Nota: Si está utilizando un argumento con guiones, estos serán reemplazados por guiones bajos en la variable de entorno correspondiente. Por ejemplo, npm run example --foo-bar=bazcorrespondería a ${npm_config_foo_bar}.

Nota: Para usuarios de Windows que no son WSL, consulte los comentarios de @Doctor Blue a continuación ... TL; DR reemplazar ${npm_config_foo}con %npm_config_foo%.

Andrew Odri
fuente
Hola. Estoy tratando de usar tu ejemplo, pero me temo que no funciona para mí. Puedo copiar-pegar el script "argumento", e hice lo mismo para el comando a ejecutar ( npm run argument --foo=bar), pero la variable no se sustituye: "The value of --foo is '${npm_config_foo}'". Ejecutando en Windows 10 si eso importa, con la versión 6.9.0 de NPM.
Doctor Blue
@DoctorBlue Ahh bien, Node y Windows no siempre funcionan bien ... Este artículo podría arrojar algo de luz sobre las variables de entorno en los scripts npm: (TL; los comandos DR van directamente al sistema operativo host, incluso si se inician desde otro shell) blog .risingstack.com / node-js-windows-10-tutorial / ... No estoy seguro de su configuración, pero si está usando Git Bash para ejecutar Node, puede considerar ejecutarlo a través de documentos
Andrew Odri
1
Me lo imaginé. Solo tenía que usar %npm_config_foo%en su lugar. Línea de comandos de Windows pura / powershell aquí. (Tampoco tengo otra opción.)
Doctor Blue
6

Esto realmente no responde a su pregunta, pero siempre puede usar variables de entorno:

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

Luego, en su archivo server.js:

var port = process.env.PORT || 3000;
Escarabajo Borracho
fuente
1
Esto es bueno siempre que esté en una plataforma Unix. Desafortunadamente, no funciona con Windows, ya que tiene una convención propia.
Juho Vepsäläinen
6

La mayoría de las respuestas anteriores cubren simplemente pasar los argumentos a su script NodeJS, llamado por npm. Mi solución es para uso general.

Simplemente envuelva el script npm con una shllamada de intérprete de shell (por ejemplo ) y pase los argumentos como de costumbre. La única excepción es que el primer número de argumento es 0.

Por ejemplo, desea agregar el script npm someprogram --env=<argument_1>, donde someprogramsolo imprime el valor del envargumento:

package.json

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

Cuando lo ejecutas:

% npm run -s command my-environment
my-environment
Alexandr Priezzhev
fuente
¡Gracias! ¡Esto fue perfecto!
Felipe Desiderati
Simple y elegante! no funcionará en un shell de MS DOS.
n370
3

Por lo que veo, la gente usa los scripts package.json cuando les gustaría ejecutar el script de una manera más simple. Por ejemplo, para usar nodemonel instalado en node_modules local, no podemos llamar nodemondirectamente desde el cli, pero podemos llamarlo usando ./node_modules/nodemon/nodemon.js. Entonces, para simplificar esta escritura larga, podemos poner esto ...

    ...

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

    ...

... luego llame npm startpara usar 'nodemon' que tiene app.js como primer argumento.

Lo que estoy tratando de decir, si solo quieres iniciar tu servidor con el nodecomando, no creo que necesites usarlo scripts. Mecanografía npm starto node app.jstiene el mismo esfuerzo.

Pero si quiere usar nodemon, y quiere pasar un argumento dinámico, no use scripttampoco. Intenta usar el enlace simbólico en su lugar.

Por ejemplo, utilizando la migración con sequelize. Creo un enlace simbólico ...

ln -s node_modules/sequelize/bin/sequelize sequelize

... Y puedo pasar cualquier argumento cuando lo llamo ...

./sequlize -h /* show help */

./sequelize -m /* upgrade migration */

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

etc ...

En este punto, usar el enlace simbólico es la mejor manera de entenderlo, pero realmente no creo que sea la mejor práctica.

También espero tu opinión a mi respuesta.

Kiddo
fuente
1
Esto no responde a la pregunta en absoluto. No sé cómo obtuvo 6 votos a favor, pero felicidades :)
Dan Dascalescu
2

Nota: este enfoque modifica su package.jsonsobre la marcha, úselo si no tiene otra alternativa.

Tuve que pasar argumentos de línea de comando a mis scripts que eran algo así como:

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

Entonces, esto significa que comienzo mi aplicación con npm run start.

Ahora, si quiero pasar algunos argumentos, comenzaría con quizás:

npm run start -- --config=someConfig

Lo que esto hace es: npm run build && npm run watch -- --config=someConfig. El problema con esto es que siempre agrega los argumentos al final del guión. Esto significa que todos los scripts encadenados no obtienen estos argumentos (Args puede o no ser requerido por todos, pero esa es una historia diferente). Además, cuando se invocan los scripts vinculados, esos scripts no obtendrán los argumentos pasados. es decir, el watchscript no obtendrá los argumentos pasados.

El uso de producción de mi aplicación es como .exe, por lo que pasar los argumentos en el exe funciona bien, pero si desea hacer esto durante el desarrollo, se vuelve problamático.

No pude encontrar ninguna manera adecuada de lograr esto, así que esto es lo que he intentado.

He creado un archivo javascript: start-script.jsen el nivel primario de la aplicación, tengo un "default.package.json" y en lugar de mantener "package.json", mantengo "default.package.json". El propósito de start-script.jsones leer default.package.json, extraer scriptsy buscar y npm run scriptnameluego agregar los argumentos pasados ​​a estos scripts. Después de esto, creará uno nuevo package.jsony copiará los datos de default.package.json con scripts modificados y luego llamará 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);
}

Ahora, en lugar de hacerlo npm run start, hagonode start-script.js --c=somethis --r=somethingElse

La ejecución inicial se ve bien, pero no se ha probado a fondo. Úselo, si lo desea para su desarrollo de aplicaciones.

Ashish Ranjan
fuente
1

Encontré esta pregunta mientras intentaba resolver mi problema con la ejecución del comando sequelize seed: generate cli:

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

Déjame llegar al punto. Quería tener un breve comando de script en mi archivo package.json y proporcionar el argumento --name al mismo tiempo

La respuesta vino después de algunos experimentos. Aquí está mi comando en package.json

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

... y aquí hay un ejemplo de cómo ejecutarlo en la terminal para generar un archivo semilla para un usuario

> yarn seed:generate --name=user

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

FYI

yarn -v
1.6.0

npm -v
5.6.0
Serge Seletskyy
fuente
2
¿Es esta la misma técnica que la explicada en la respuesta aceptada en 2013 para aprobar -- --arg1, ...?
Dan Dascalescu
2
OK, entonces ¿por qué repetir la respuesta?
Dan Dascalescu
He compartido un claro ejemplo de uso, ¿no es obvio?
Serge Seletskyy
2
Si quisiera compartir otro ejemplo para una técnica ya explicada en una respuesta diferente, agregaría mi ejemplo como comentario a esa respuesta.
Dan Dascalescu
1
gotcha, lo haré la próxima vez
Serge Seletskyy
0

npm run script_target - <argumento> Básicamente esta es la forma de pasar los argumentos de la línea de comando, pero funcionará solo en caso de que el script tenga un solo comando ejecutándose como si estuviera ejecutando un comando, es decir, npm run start - 4200

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

Esto se ejecutará para pasar los parámetros de la línea de comandos, pero ¿y si ejecutamos más de un comando juntos como npm run build c: / workspace / file?

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

pero interpretará de esta manera mientras ejecuta copy c: / file && ng build c: / work space / file y se espera que sea algo así como copy c: / file c: / work space / file && ng build

Nota: - por lo tanto, el parámetro de línea de comando solo funciona el anuncio esperado en el caso de un solo comando en un script.

Leí algunas respuestas anteriores en las que algunas de ellas escriben que puedes acceder al parámetro de línea de comando usando el símbolo $ pero esto no funcionará

Sunny Goel
fuente
0

Sé que ya hay una respuesta aprobada, pero me gusta este enfoque JSON.

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

Por lo general, tengo como 1 var que necesito, como el nombre de un proyecto, por lo que me parece rápido y simple.

También a menudo tengo algo como esto en mi paquete.json

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

Y siendo codicioso, quiero "todo", NODE_ENV y la línea arg de CMD.

Simplemente accede a estas cosas como tal en su archivo (en mi 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);

Solo necesita tener este bit por encima (estoy ejecutando v10.16.0 por cierto)

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

Anyhoo, pregunta ya respondida. Pensé en compartir, ya que uso mucho este método.

fullstacklife
fuente