GitHunt
MA

mahemoff/node-config-demo

How to read options from command line, config files, and mix both. With Node and Yargs.

node-config-demo

How to read options from command line, config files, and mix both. With Node and Yargs.

YARGS is a powerful tool if you're building anything complex with Node. One of the best things is it not only looks at command-line arguments, but config files, and it's even possible to mix them together.

I created this project because I wanted to explore how all of this works. How is a conflicts handled in a situation where the same argument is specified in multiple placs? How does all this work when there are nested hashes (i.e. a hierarchy of options, not just a simple, flat, list). And how to deal with config files flexibly, not just the standard idea of a JSON file at a location specified by the user.

The yargs invocations can be found in lib/ folder. This doc is generated by the bash script demo.sh, which runs the scripts with various arguments to demonstrate each usage pattern.

BASE CASE

NO ARGUMENTS

No app-specific variables are set.

demo.js

{
  "_": [],
  "$0": "lib/demo.js"
}

--

COMMAND LINE ARGUMENTS

COMMAND-LINE ARGUMENTS

Variables set directly from command line. Note that a dashed-option gives you both camelCase and snake_case references as a convenience.

demo.js --time=60 --splash-screen=false

{
  "_": [],
  "time": 60,
  "splash-screen": "false",
  "splashScreen": "false",
  "$0": "lib/demo.js"
}

--

NESTED COMMAND LINE ARGUMENTS

Specify hierarchies using dot notation.

demo.js --time=60 --splash-screen=false --enemy.speed=50 --enemy.visible=true --player.speed=20 --player.human=true

{
  "_": [],
  "time": 60,
  "splash-screen": "false",
  "splashScreen": "false",
  "enemy": {
    "speed": 50,
    "visible": "true"
  },
  "player": {
    "speed": 20,
    "human": "true"
  },
  "$0": "lib/demo.js"
}

--

CONFIG FILE

SIMPLE CONFIG FILE

Instead of using command-line, its possible to include options in a file with yargs config() method.

demo.js --config=config/game.json

{
  "_": [],
  "config": "config/game.json",
  "time": 30,
  "splash-screen": true,
  "splashScreen": true,
  "enemy": {
    "speed": 100,
    "visible": false
  },
  "player": {
    "speed": 30,
    "human": false
  },
  "$0": "lib/demo.js"
}

--

TOML CONFIG FILE

It doesnt have to be a JSON file. Any format can be used as long as theres a way to parse itng into a hash, so well use a different config() here to support TOML instead.

toml_demo.js --config=config/game.toml

{
  "_": [],
  "config": "config/game.toml",
  "time": 45,
  "splash-screen": true,
  "splashScreen": true,
  "enemy": {
    "speed": 100,
    "visible": false
  },
  "player": {
    "speed": 40,
    "visible": true
  },
  "$0": "lib/toml_demo.js"
}

--

FLEXIBLE CONFIG FILES

In this case, config() has been modified to support looking for config in standard locations. You can try making a JSON file (with any content) at ~/.game.json and re-running the demo.

flexible_config_demo.js

{
  "_": [],
  "foo": "bar",
  "config": "/dev/null",
  "$0": "lib/flexible_config_demo.js"
}

--

MIXING COMMAND LINE ARGUMENTS WITH CONFIG FILE

SAME OPTION ON BOTH COMMAND LINE AND CONFIG FILE

As the results show, both config and command line are used. The config file provides defaults, which the command line can override.

demo.js --time=60 --config=config/simple_game.json

{
  "_": [],
  "time": 60,
  "config": "config/simple_game.json",
  "splash-screen": true,
  "splashScreen": true,
  "enemy": {
    "speed": 100,
    "visible": false
  },
  "player": {
    "speed": 30,
    "human": false
  },
  "$0": "lib/demo.js"
}

--

NESTED OPTIONS ON BOTH COMMAND LINE AND CONFIG FILE

Again, options present in both will be determined by the command line as it has priority. As before, options only in one or the other will still be respected, this time with nesting.

demo.js --time=60 --enemy.speed=25 --physics.gravity=5 --config=config/game.json

{
  "_": [],
  "time": 60,
  "enemy": {
    "speed": 25,
    "visible": false
  },
  "physics": {
    "gravity": 5
  },
  "config": "config/game.json",
  "splash-screen": true,
  "splashScreen": true,
  "player": {
    "speed": 30,
    "human": false
  },
  "$0": "lib/demo.js"
}

--

mahemoff/node-config-demo | GitHunt