Invio di argomenti da riga di comando allo script npm


819

La scriptsparte del mio package.jsonattualmente assomiglia a questo:

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

... il che significa che posso eseguire npm startper avviare il server. Fin qui tutto bene.

Tuttavia, vorrei essere in grado di eseguire qualcosa di simile npm start 8080e passare l'argomento / i a script.js(es. npm start 8080=> node ./script.js server 8080). È possibile?

Risposte:


1132

Modifica 2014.10.30: È possibile passare argomenti a npm runpartire da npm 2.0.0

La sintassi è la seguente:

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

Nota il necessario --. È necessario separare i parametri passati al npmcomando stesso e i parametri passati allo script.

Quindi se ci sei dentro package.json

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

Quindi i seguenti comandi sarebbero equivalenti:

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

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

Per ottenere il valore del parametro, vedere questa domanda . Per la lettura di parametri denominati, probabilmente è meglio usare una libreria di analisi come yarg o minimista ; nodejs espone a process.argvlivello globale, contenente i valori dei parametri della riga di comando, ma si tratta di un'API di basso livello (array di stringhe separato da spazi bianchi, come fornito dal sistema operativo all'eseguibile del nodo).


Modifica 2013.10.03: Al momento non è possibile direttamente. Ma c'è un problemanpm correlato a GitHub aperto per implementare il comportamento che stai chiedendo. Sembra che il consenso sia quello di implementarlo, ma dipende da un altro problema risolto in precedenza.


Risposta originale: come una sorta di soluzione alternativa (anche se non molto utile), puoi fare come segue:

Di 'la tua nome del pacchetto da package.jsonIS myPackagee hai anche

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

Quindi aggiungere package.json:

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

E nel tuo 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

In questo modo, per impostazione predefinita npm startverrà utilizzato 8080. È comunque possibile configurarlo (il valore verrà archiviato npmnella sua memoria interna):

npm config set myPackage:myPort 9090

Quindi, quando si invoca npm start, verrà utilizzato 9090 (il valore predefinito package.jsonviene sovrascritto).


1
Funziona perfettamente anche con pacchetti come yargs; tutti i parametri dopo il --possono essere analizzati perfettamente nel tuo script.
Thomas,

11
AFAIKS, questo rende possibile solo aggiungere parametri alla fine dei tuoi script .. e se avessi bisogno di parametri nel mezzo?
Spock,

109
-- --argsholy crap che è strano, ma va bene
Agosto

9
@Spock È possibile utilizzare le funzioni della shell. Ecco una configurazione di eslint + tslint che uso per consentire il passaggio di argomenti personalizzati per eslint, ad insance, tramite "npm run lint - -f unix": "lint": "f () {eslint -f codeframe $ @. && npm run tslint && echo 'lint clean!';}; f "
ecmanaut

3
Il modo migliore per impostare il valore "myPackage: myPort 9090" è con un flag di configurazione sul comando "--myPackage: myPort = 9090" - keithcirkel.co.uk/how-to-use-npm-as-a-build -TOOL
chrismarx

223

Hai chiesto di essere in grado di eseguire qualcosa del genere npm start 8080 . Ciò è possibile senza la necessità di modificare script.jso configurare i file come segue.

Ad esempio, nel tuo "scripts"valore JSON, includi--

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

E poi dalla riga di comando:

$ PORT=8080 npm start

Ho confermato che funziona usando bash e npm 1.4.23. Si noti che questa soluzione alternativa non richiede la risoluzione del problema npm 3494 di GitHub .


19
Funziona davvero bene. Puoi anche fare qualcosa di simile node ./script.js server ${PORT:-8080}per renderlo facoltativo.
attacco

7
Mi sembra di non riuscire a farlo in Windows con Git Bash. Qualcuno l'ha fatto funzionare forse? (lo stesso comando funziona su Ubuntu)
Karolis Šarapnickis,

3
Ehi, @graup, questo ha funzionato per me NODE_PORT=${PORT=8080}(notarlo in egual misura) ma non per: - sintassi
MaieonBrix

14
Questo non funziona multipiattaforma! Ad esempio su Windows il comando dovrebbe essere node ./script.js server %PORT%. Prendi in considerazione l'uso di cross-var e cross-env .
Stijn de Witt,

Il caso d'uso per usare env var come cli args mi sembra piuttosto limitato? Può anche usare qualcosa come il modulo di configurazione per gestire le impostazioni ambientali, i valori predefiniti e la configurazione in generale.
Mr5o1,

93

Potresti anche farlo:

In package.json:

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

In cool.js:

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

In CLI:

npm --myVar=something run-script cool

Dovrebbe produrre:

{ myVar: 'something' }

Aggiornamento: utilizzando npm 3.10.3, sembra che minuscole le process.env.npm_config_variabili? Sto anche utilizzando better-npm-run, quindi non sono sicuro se questo è il comportamento predefinito vaniglia o no, ma questa risposta sta lavorando. Invece di process.env.npm_config_myVarprovareprocess.env.npm_config_myvar


4
Grazie ha funzionato per me! Quello che mi mancava in particolare il prefisso "npm_config_" al nome della variabile che si sta specificando nella riga di comando.
jp093121,

2
Questo è sbagliato. process.env.npm_config_myVarrestituisce vero, non il valore.
Karl Morrison,

1
Funziona con npm versione 6.8.0 ma solo quando ho usato lettere minuscole per il nome della variabile. sembra lilke npm cambiarlo in minuscolo
Ofir Meguri,

Ottima soluzione, funziona con il parametro minuscolo su npm 6.5.0
GavinBelson

78

La risposta di jakub.g è corretta, tuttavia un esempio che utilizza grunt sembra un po 'complesso.

Quindi la mia risposta più semplice:

- Invio di un argomento della riga di comando a uno script npm

Sintassi per l'invio di argomenti della riga di comando a uno script npm:

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

Immagina di avere un'attività npm start nel nostro pacchetto.json per dare il via al server dev webpack:

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

Lo eseguiamo dalla riga di comando con npm start

Ora, se vogliamo passare in una porta allo script npm:

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

l'esecuzione di questo e il passaggio della porta, ad esempio 5000 tramite riga di comando, sarebbe il seguente:

npm start --port:5000

- Utilizzo di package.json config:

Come accennato da jakub.g , puoi alternativamente impostare i parametri nella configurazione di package.json

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

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

npm start utilizzerà la porta specificata nella configurazione o, in alternativa, è possibile sostituirla

npm config set myPackage:myPort 3000

- Impostazione di un parametro nel tuo script npm

Un esempio di lettura di una variabile impostata nello script npm. In questo esempioNODE_ENV

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

leggi NODE_ENV in server.js sia prod che dev

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

if(env === 'dev'){
    var app = require("./serverDev.js");
} else {
    var app = require("./serverProd.js");
}

5
nota che la sintassi come "start:prod": "NODE_ENV=prod node server.js"in package.jsonnon funzionerà su Windows, a meno che tu non usi cross-env
jakub.g

2
Correzione ?: "start": "webpack-dev-server --port process.env.npm_package_config_myPort || 8080" },dovrebbe essere "start": "webpack-dev-server --port $npm_package_config_myPort || 8080" },secondo il mio uso spiegato da questo tutorial . Il processo ref può essere apparentemente utilizzato all'interno di JavaScript.
Aaron Roller,

35

npm 2.x support cli args

Comando

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

Package.json

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

Index.js

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


1
La risposta accettata (data un anno prima di questa) menziona già questa tecnica.
Dan Dascalescu,

34

Utilizzare process.argvnel proprio codice quindi fornire solo un trascinamento $*alla voce del valore degli script.

Ad esempio, provalo con un semplice script che registra semplicemente gli argomenti forniti su standard out echoargs.js:

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

package.json:

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

Esempi:

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

process.argv[0]è l'eseguibile (nodo), process.argv[1]è il tuo script.

Testato con npm v5.3.0 e nodo v8.4.0


Non funziona dopo l'aggiunta --agli argomenti, ad esempio - npm run demo.js --skip, funziona se aggiunto un extra --, ad esempio -npm run demo.js -- --skip
Shreyas

Puoi usare questo metodo senza avere un echoargs.jsfile di script separato ?
Joshua Pinter,

@JoshuaPinter echoargs.js è solo un esempio, modificherò la mia risposta per chiarirlo
Peter

@Peter Right, ma deve essere un file di script. Sto cercando di creare uno script che utilizza adbper .dbinviare un file all'emulatore Android e accetta un parametro per il percorso locale del .dbfile da inviare ad esso, che è il primo parametro di adb push. Qualcosa del genere: "db:push": "adb push process.argv.slice(2) /data/data/com.cntral.app/databases/database.db"e voglio chiamarlo con npm run db:push /Users/joshuapinter/Downloads/updated.db. qualche idea?
Joshua Pinter,

21

Se si desidera passare gli argomenti nel mezzo di uno script npm, invece di averli aggiunti alla fine, le variabili di ambiente inline sembrano funzionare bene:

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

Qui, npm run devpassa la -wbandiera dell'orologio a babele, ma npm run startesegue solo una build normale una volta.


Come viene chiamato dalla CLI?
bwobst,

@dresdin npm run dev,npm start
TJ

2
Devi usare cross-env per usarlo su Windows.
fracz,

8

Avevo usato questo one-liner in passato e dopo un po 'di tempo lontano da Node.js ho dovuto provare a riscoprirlo di recente. Simile alla soluzione menzionata da @francoisrv, utilizza le node_config_*variabili.

Creare il seguente package.jsonfile minimo :

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

Esegui il seguente comando:

npm run argument --foo=bar

Osservare il seguente output:

Il valore di --foo è 'bar'

Tutto ciò è ben documentato nella documentazione ufficiale di npm:

Nota: l' intestazione Variabili d'ambiente spiega che le variabili all'interno degli script si comportano in modo diverso da quanto definito nella documentazione. Questo è vero quando si tratta della distinzione tra maiuscole e minuscole , anche se l'argomento è definito con uno spazio o è uguale a segno .

Nota: se si utilizza un argomento con trattini, questi verranno sostituiti con caratteri di sottolineatura nella corrispondente variabile di ambiente. Ad esempio, npm run example --foo-bar=bazcorrisponderebbe a ${npm_config_foo_bar}.

Nota: per gli utenti di Windows non WSL, vedere i commenti di @Doctor Blue di seguito ... TL; DR sostituire ${npm_config_foo}con %npm_config_foo%.


Ciao. Sto tentando di usare il tuo esempio ma temo che non funzioni per me. Ho copiato e incollato il tuo script "argomento" e ho fatto lo stesso per il comando run ( npm run argument --foo=bar), ma la variabile non è stata sostituita:"The value of --foo is '${npm_config_foo}'" . In esecuzione su Windows 10 se è importante, con la versione 6.9.0 di NPM.
Dottor Blue

@DoctorBlue Ahh, Nodo e Windows non giocano sempre bene ... Questo articolo potrebbe far luce sulle variabili d'ambiente negli script npm: (TL; i comandi DR vanno direttamente al sistema operativo host, anche se lanciati da un'altra shell) blog .risingstack.com / node-js-windows-10-tutorial / ... Non sono sicuro della tua configurazione, ma se stai usando Git Bash per eseguire Node, potresti considerare di eseguirlo tramite i documenti
Andrew Odri

1
L'avevo capito. Dovevo solo usare %npm_config_foo%invece. Riga di comando / powershell di Windows pura qui. (Non ho scelta.)
Dottor Blue

6

Questo in realtà non risponde alla tua domanda, ma puoi sempre utilizzare le variabili di ambiente:

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

Quindi nel tuo file server.js:

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

1
Questo va bene finché sei su una piattaforma Unix. Sfortunatamente non funziona con Windows in quanto ha una convenzione propria.
Juho Vepsäläinen,

6

La maggior parte delle risposte di cui sopra copre il semplice passaggio degli argomenti nello script NodeJS, chiamato da npm. La mia soluzione è per uso generale.

Basta avvolgere lo script npm con una shchiamata dell'interprete della shell (ad es. ) E passare gli argomenti come al solito. L'unica eccezione è che il primo numero argomento è0 .

Ad esempio, si desidera aggiungere lo script npm someprogram --env=<argument_1>, in cui viene someprogramsemplicemente stampato il valore dienv dell'argomento:

package.json

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

Quando lo esegui:

% npm run -s command my-environment
my-environment

Grazie! Questo è stato perfetto!
Felipe Desiderati,

Semplice ed elegante! non funzionerà su una shell MS DOS.
n. 3

3

Da quello che vedo, le persone usano gli script package.json quando vorrebbero eseguire gli script in modo più semplice. Ad esempio, per usare nodemonquello installato in node_modules locali, non possiamo chiamare nodemondirettamente dal cli, ma possiamo chiamarlo usando ./node_modules/nodemon/nodemon.js. Quindi, per semplificare questa digitazione lunga, possiamo mettere questo ...

    ...

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

    ...

... quindi chiama npm startper usare 'nodemon' che ha app.js come primo argomento.

Quello che sto cercando di dire, se vuoi solo avviare il tuo server con il nodecomando, non penso che tu debba usare scripts. Digitare npm starto node app.jsha lo stesso sforzo.

Ma se vuoi usare nodemone vuoi passare un argomento dinamico, non usare scriptneanche. Prova invece a utilizzare il collegamento simbolico.

Ad esempio utilizzando la migrazione con sequelize. Creo un link simbolico ...

ln -s node_modules/sequelize/bin/sequelize sequelize

... E posso passare qualsiasi argomento quando lo chiamo ...

./sequlize -h /* show help */

./sequelize -m /* upgrade migration */

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

eccetera...

A questo punto, usare il collegamento simbolico è il modo migliore che ho potuto capire, ma non penso davvero che sia la migliore pratica.

Spero anche per la tua opinione alla mia risposta.


1
Questo non risponde affatto alla domanda. Non so come abbia ottenuto 6 voti positivi, ma congratulazioni :)
Dan Dascalescu,

2

Nota: questo approccio modifica il tuopackage.json al volo, usalo se non hai alternative.

Ho dovuto passare argomenti della riga di comando ai miei script che erano qualcosa del tipo:

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

Quindi, questo significa che inizio la mia app con npm run start.

Ora, se voglio passare alcuni argomenti, inizierei forse:

npm run start -- --config=someConfig

Quello che fa è: npm run build && npm run watch -- --config=someConfig. Il problema è che aggiunge sempre gli argomenti alla fine dello script. Questo significa che tutti gli script concatenati non ottengono questi argomenti (Args forse o potrebbe non essere richiesto da tutti, ma questa è una storia diversa). Inoltre, quando vengono chiamati gli script collegati, tali script non riceveranno gli argomenti passati. cioè lo watchscript non otterrà gli argomenti passati.

L'utilizzo di produzione della mia app è come .exe , quindi passare gli argomenti in exe funziona bene ma se vuoi farlo durante lo sviluppo, diventa problematico.

Non sono riuscito a trovare un modo adeguato per raggiungere questo obiettivo, quindi questo è quello che ho provato.

Ho creato un file javascript: start-script.jsa livello padre dell'applicazione, ho un "default.package.json" e invece di mantenere "package.json", mantengo "default.package.json". Lo scopo di start-script.jsonè leggere default.package.json, estrarre scriptse cercare, npm run scriptnamequindi aggiungere gli argomenti passati a questi script. Successivamente, ne creerà uno nuovo package.jsone copierà i dati da default.package.json con script modificati e quindi chiamerà 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);
}

Ora, invece di farlo npm run start, lo faccionode start-script.js --c=somethis --r=somethingElse

La corsa iniziale sembra a posto, ma non è stata testata accuratamente. Usalo, se ti piace per lo sviluppo di app.


1

Ho trovato questa domanda mentre cercavo di risolvere il mio problema con l'esecuzione del seed sequelize: generate cli comando:

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

Vorrei arrivare al punto. Volevo avere un breve comando di script nel mio package.json file e fornire contemporaneamente --name argomento

La risposta è arrivata dopo alcuni esperimenti. Ecco il mio comando in package.json

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

... ed ecco un esempio di esecuzione nel terminale per generare un file seme per un utente

> yarn seed:generate --name=user

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

FYI

yarn -v
1.6.0

npm -v
5.6.0

2
È la stessa tecnica di quella spiegata nella risposta accettata nel 2013, per passare -- --arg1, ...?
Dan Dascalescu,

2
OK, allora perché ripetere la risposta?
Dan Dascalescu,

Ho condiviso un chiaro esempio di utilizzo, non è ovvio?
Serge Seletskyy,

2
Se volessi condividere un altro esempio per una tecnica già spiegata in una risposta diversa, aggiungerei il mio esempio come commento a quella risposta.
Dan Dascalescu,

1
gotcha, lo farà la prossima volta
Serge Seletskyy il

0

npm run script_target - <argomento> Fondamentalmente questo è il modo di passare gli argomenti della riga di comando ma funzionerà solo nel caso in cui lo script abbia un solo comando in esecuzione come se stessi eseguendo un comando, cioè npm run start - 4200

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

Questo verrà eseguito per il passaggio dei parametri della riga di comando ma cosa succede se eseguiamo più di un comando insieme come npm run build c: / workspace / file

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

ma interpreterà in questo modo durante l'esecuzione della copia c: / file && ng build c: / spazio di lavoro / file e ci si aspetta qualcosa di simile a questa copia c: / file c: / spazio di lavoro / file && ng build

Nota: - quindi il parametro della riga di comando funziona solo con l'annuncio previsto nel caso di un solo comando in uno script.

Ho letto alcune risposte sopra in cui alcuni di loro stanno scrivendo che è possibile accedere al parametro della riga di comando usando $ simbolo ma questo non funzionerà


0

So che esiste già una risposta approvata, ma mi piace un po 'questo approccio JSON.

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

Di solito ho 1 var di cui ho bisogno, come il nome di un progetto, quindi trovo questo veloce e semplice.

Inoltre ho spesso qualcosa di simile nel mio package.json

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

Ed essendo avido voglio "tutto", NODE_ENV e la roba arg della linea CMD.

Accedi semplicemente a queste cose nel tuo file (nel mio 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);

Hai solo bisogno di avere questo bit sopra di esso (sto eseguendo v10.16.0 btw)

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

Anyhoo, domanda già risposta. Ho pensato di condividere, poiché uso molto questo metodo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.