Luciano M. L.
Luciano M. L.

Reputation: 779

Pass command line -- argument to child script in Yarn

I have a package.json that looks similar to this:

"scripts": {
    "dev": "cross-env BABEL_ENV=client webpack --config webpack/client.development.js && yarn dev:stub-server | cross-env BABEL_ENV=server babel-node src/server/server.js",
    "dev:stub-server": "./node_modules/.bin/robohydra ./stubs/robohydra-config.json -p 3100"
}

I added some logic in the code to change the way the dev:stub-server is configured depending on a command line argument. So, whenever I run the following I get what I expect:

yarn dev:stub-server --results=4
$ ./node_modules/.bin/robohydra ./stubs/robohydra-config.json -p 3100 -- --results=4

As you can see, the options are forwarded to the underlying script and everything works as expected.

My problem is that I cannot have the --results propagated from the yarn dev command to dev:stub-server in the correct position. The parent script runs dev:stub-server but the argument is forwarded to the underlying script at the end as follows:

yarn dev --results=2
$ cross-env BABEL_ENV=client webpack --config webpack/client.development.js && yarn dev:stub-server | cross-env BABEL_ENV=server babel-node src/server/server.js --results=2

Is there a way to make the above work as follows instead?

yarn dev --results=2
$ cross-env BABEL_ENV=client webpack --config webpack/client.development.js && yarn dev:stub-server --results=2 | cross-env BABEL_ENV=server babel-node src/server/server.js

Thanks in advance!

Upvotes: 55

Views: 83386

Answers (13)

Sparm
Sparm

Reputation: 566

Create a build script like this (place in same dir as your package.json):

// build.js
import cp from "child_process";
const env = Object.create(process.env);
// Replace the command in execSync with whatever you would put in your package.json script and use argv[2] onwards to reference passed in command line variables
cp.execSync(`tsc -b && vite build --mode ${process.argv[2]}`, { env: env, stdio: 'inherit' })

Then in your package.json scripts:

scripts:{
   "build":"node build.js"
}

Then pass in params like this:

yarn run build yourmom

Not tested it on Mac and Linux, but works in Windows

Upvotes: 0

Etheryte
Etheryte

Reputation: 25310

A straightforward way to achieve this is to write an inline Bash function using parameter expansion with $@:

"scripts": {
    "dev": "wrap () { node index.js \"$@\" | cat; }; wrap"
}

Calling the above with yarn dev foo bar will run node index.js foo bar and then pipe the result into cat as a demo.
You can tack on commands both to the start and the end, simply keep in mind that semis are required here.

For anything more involved you'll probably want a standalone script.

Upvotes: 27

You can dissect your script in preScript, Script and postScript.

Example with a git typescript library project i have:

"predodeploy": "yarn build",
"dodeploy": "yarn config set version-git-message ",
"postdodeploy": "yarn version --minor && yarn config set version-git-message 'v%s'"

and then run

yarn dodeploy "my custom message"       

Upvotes: -1

rebinnaf
rebinnaf

Reputation: 513

If you are using yarn 1.x, this might help you: https://github.com/yarnpkg/yarn/issues/5207#issuecomment-690583826

Notice: it only works on shell, not windows :)

For instance I wanted to add args to standard version message(-m):

I changed it from

"release:beta": "yarn test && standard-version --prerelease beta && git push --follow-tags",

to

"release:beta": "f() { yarn test && standard-version --prerelease beta -m \"$@\" && git push --follow-tags; }; f",

Upvotes: 1

Édouard Lopez
Édouard Lopez

Reputation: 43391

Create a wrapper function for your command, this way you can control the position of your arguments:

  "scripts": {
    "audit-page": "wrapper() { lighthouse $1 --chrome-flags='--headless'; }; wrapper "
  },

Then I can use:

yarn audit-page https://example.com

And it results in the following call:

$ wrapper() { lighthouse $1 --chrome-flags='--headless'; }; wrapper  https://example.com

Otherwise lighthouse complain as it expect the URL before options

Upvotes: 0

CodingWithSpike
CodingWithSpike

Reputation: 43698

Yarn "modern" (v2+) supports passing the arguments:

"scripts": {
  "args": "echo \"second $1 first $0 all $@\""

output:

$ yarn run args 1 2
second 2 first 1 all 1 2

Upvotes: -4

nroose
nroose

Reputation: 1792

I used the file workaround, but then discovered that I can append parameters to the command using -- before the parameters. So, with the normal command in the package.json file, then yarn run cmd -- --param value I got it working.

Upvotes: -2

Artem Kozlenkov
Artem Kozlenkov

Reputation: 1244

use the npm ability to pass named custom arguments to command line as a proxy for your yarn commands:

 "scripts": {
      "yarn-cmd": "npm run npm-cmd --foo=bar",
      "npm-cmd": "echo \"foo value is $npm_config_foo\""
    }

run yarn yarn-cmd

read more: https://docs.npmjs.com/cli/v7/using-npm/config

Upvotes: 1

Ivan Gonzalez
Ivan Gonzalez

Reputation: 576

As for now, using yarn 1.22.4 you can do yarn exec tsc -- --help. Appending the -- does the trick

Upvotes: 3

W.Perrin
W.Perrin

Reputation: 4685

Do it like these. As yarn will deliver parameters essentially.

"scripts": {
  "runSomeShellScriptAlpha": "path/to/script_name.sh  $1 $2 $3", // redundant $x
  "runSomeShellScriptBeta": "path/to/script_name.sh",            // better 
}
yarn runSomeShellScriptBeta p1 p2 p3

The alpha one works only on Mac/Linux, not on Win10. It's bad.

The beta one works both on Mac/Linux and Win10.

Upvotes: 1

Daniel Einars
Daniel Einars

Reputation: 152

As an alternative you could use a *.env file and cat the variables out of it in your script.

"run":"docker build -t --build-arg VAR=`cat vars.env` -f Dockerfile .

for example

Upvotes: 4

Philippe
Philippe

Reputation: 1039

On mac I am using:

"scripts": {
  "benchmark": "sh -c 'ng run ${0}:benchmark'",
}

Which I then call yarn benchmark editor where editor is my parameter.

Upvotes: 59

mrm
mrm

Reputation: 5212

Yarn's run only supports appending your args to the end of the command chain, and at least as of date 2018-06-14, there isn't a way to override that.

When I've needed this in the past, I've cooked up my own dev.js script that was called by my package.json, and pulled args out environment variables.

Upvotes: 30

Related Questions