48

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!

RobC
  • 22,977
  • 20
  • 73
  • 80
Luciano M. L.
  • 709
  • 1
  • 5
  • 9

12 Answers12

48

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.

Philippe
  • 861
  • 10
  • 10
  • 4
    This will fail on windows, of course, unless you can tell everyone using your package that they need to install `bash` (either via cygwin or git for windows). I don't think this is reasonable for open source, but I use it all over the place for my closed-source project. – mrm Apr 06 '19 at 19:59
  • Hi, this is awesome, but can I pass the argument to somewhere inside executed script? I need something like `yarn semistandard --fix $(git diff --name-only HEAD HEAD~${0})` – Zennichimaro Sep 17 '20 at 03:10
  • Holy crap this saved me - thank you SO MUCH! Do you know why it starts at 0 not 1 though? – Geoff Davids Oct 06 '21 at 15:04
  • 1
    So is there a way to do this on Windows without bash? – marvc1 May 03 '22 at 12:22
  • With this, the default value will be "sh". Any ideas to override the default value if nothing is provided? – kitta Mar 17 '23 at 18:09
29

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.

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
mrm
  • 5,001
  • 2
  • 32
  • 30
25

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.

Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • 1
    @Etheryte I'm missing something very basic here. On Windows, I'm running similar inline bash function in git bash, but getting `wrap is not recognized as an internal or external command...`. Any idea what could cause that? – M.Pogorzelski Jan 31 '22 at 15:17
  • 1
    For anyone encountering the same issue as a YARN user. Yarn by default uses `bin\sh`, in which this particular inline Bash function cannot be run. You need to set Yarn to use `bin\bash` by executing this `yarn config set script-shell bin\bash` – M.Pogorzelski Feb 01 '22 at 13:04
  • For those who use this solution, `"wrap () { node index.js $* | cat; }; wrap"` try this if it doesn't work without any parameters – shapeless Mar 28 '22 at 06:47
  • I would recommend using `"$@"` instead of `"$*"` or `$*`, since it'll work properly with multiple parameters, no parameters, and parameters that contain whitespace (the other variants mess some or all of these up). – Gordon Davisson Jun 07 '23 at 21:45
  • @GordonDavisson Thanks a lot for the heads up, I was not aware of the difference. I've updated the answer. For anyone else wanting to read up more about it, see [this question](https://unix.stackexchange.com/q/41571/22607) for more details. – Etheryte Jun 08 '23 at 09:26
3

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

Daniel Einars
  • 133
  • 14
  • Args didn't work for me. I put them in files and cat-ed them and that worked. Then I found this. – nroose Oct 26 '22 at 03:37
3

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

Ivan Gonzalez
  • 446
  • 1
  • 5
  • 14
1

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.

W.Perrin
  • 4,217
  • 32
  • 31
  • This isn't working for me -- it doesn't replace `{script_name}` -- is it possible I'm missing something? – slifty Aug 27 '20 at 16:20
  • `{script_name}` means a customed file name. It is not a variable and won't be substituted by `shell`. Sorry for the brackets leading misunderstanding – W.Perrin Aug 28 '20 at 01:50
1

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

Artem Kozlenkov
  • 975
  • 9
  • 11
1

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",
rebinnaf
  • 276
  • 2
  • 9
0

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

Édouard Lopez
  • 40,270
  • 28
  • 126
  • 178
-1

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"       
  • Can you elaborate? What is `v%s`? Why is `set` called twice? What happens when the command is run? – Raphael Sep 27 '21 at 18:44
  • 1
    Frank, this is because yarn or npm version command has his own commit message specified by version-git-message git parameter, and by default his value is 'v%s'. This parameter 'v%s', is the version number. So when i do dodeploy "my custom message", im setting version-git-message parameter form 'v%s'. to "my custom message". Before that, a yarn build command is executed. and after dodeploy script is completed, postdeploy command is executed. here im only restoring default version-git-message parameter. – Felipe Rodriguez Herrera Sep 28 '21 at 14:11
-1

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.

nroose
  • 1,689
  • 2
  • 21
  • 28
-3

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
CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138