{"componentChunkName":"component---src-templates-post-js","path":"/post/using-node-js-to-create-powerful-beautiful-user-friendly-clis","result":{"data":{"contentfulHero":{"coverImage":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/1jqMTE2RJBiMLIcZAnu6It/5495c6ec7df10a55768df442e73fe4b2/home-hero-min.jpg","fileName":"home-hero-min.jpg"}}}},"pageContext":{"post":{"id":"a990c3f0-e2d6-5af8-9fb0-5210989de64a","slug":"using-node-js-to-create-powerful-beautiful-user-friendly-clis","title":"Using Node.js to Create Powerful, Beautiful, User-Friendly CLIs","createdAt":"Jun 04, 2020","tweetText":null,"type":"blog","video":null,"podcast":null,"categories":[{"id":"a397ebc3-492b-5568-b45d-6d4aa9722be7","name":"Tutorials","slug":"tutorials"},{"id":"4384d042-dd09-5c7b-967b-95eab1334a2c","name":"Node.js","slug":"node-js"}],"image":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/75co1EpxpG1rhe3sWnLm87/1651df38aa7d98def17622f5c3660fd3/11-min.png","fileName":"11-min.png"}},"author":{"name":"Adrián Estrada","bio":{"childMarkdownRemark":{"html":"<p>Developer in love with Node.js, thirsty for new technologies, leading the charge @NodeSource - organizer @MedellinJS, @JSConfCO and @NodeConfCO.</p>"}},"avatar":{"file":{"fileName":"personal-min.jpg","url":"//images.ctfassets.net/xmu5vdhtphau/2Halso4GK0aFRLRkQK0gbj/847adfa3e4c08ef3a825166fb41aaabe/personal-min.jpg"}}},"bodyContent":{"childMarkdownRemark":{"html":"<p>Not every Node.js application is meant to live in the web; Node.js is a popular runtime allowing you to write multiple types of applications running on a variety of  platforms—from the cloud to many IoT devices. Naturally, Node.js can also run in your local shell, where powerful tools can perform magic, executing useful tasks enhancing your developer capabilities.</p>\n<p>A Command Line Interface (CLI), can perform anything from a simple operation—like printing ASCII art in the terminal like <a href=\"https://www.npmjs.com/package/yosay\">yosay</a>—to entirely generating the code for a project based on your choices using multiple templates like <a href=\"https://www.npmjs.com/package/yo\">Yeoman yo</a>. These programs can be installed globally from npm,  or executed directly using  <code>npx</code> if they are simple enough.</p>\n<p>Let's explore the basics of building a simple CLI using Node.js. In this example, we’re creating a simple command which receives a name as an argument displaying an emoji and a greeting.</p>\n<p>The first thing you should do as in every application is to create a folder for it and execute:</p>\n<pre><code>$ npm init\n</code></pre>\n<p>The previous command will ask for some information like the package name, version, license, and others creating the <code>package.json</code> at the end, looking like this:</p>\n<pre><code class=\"language-json\">{\n  \"name\": \"hello-emoji\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A hello world CLI with a nice emoji\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" &#x26;&#x26; exit 1\"\n  },\n  \"author\": \"edsadr\",\n  \"license\": \"MIT\"\n}\n</code></pre>\n<p>As we want our CLI to be available as a command, we need to configure our <code>package.json</code> to treat our program like that, to do it we add a <code>bin</code> section like this:</p>\n<pre><code class=\"language-json\">\"bin\": {\n  \"hello-emoji\": \"./index.js\"\n}\n</code></pre>\n<p>In this case, <code>hello-emoji</code> is the command we are registering to execute our program, and <code>./index.js</code> is the file to be executed when the command is invoked.</p>\n<p>To display emojis, let's add a package:</p>\n<pre><code>$ npm install node-emoji -S\n</code></pre>\n<p>Now, let's  create the file to be executed, <code>index.js</code>:</p>\n<pre><code class=\"language-javascript\">#!/usr/bin/env node\n'use strict'\n\nconst emojis = require('node-emoji')\n\nif (!process.argv[2]) {\n  console.error(`${emojis.get('no_entry')} Please add your name to say hello`)\n  process.exit(1)\n}\n\nconsole.log(`${emojis.random().emoji}  Hello ${process.argv['2']}!`)\n</code></pre>\n<p>Note that we add <code>#!/usr/bin/env node</code> at the top. This tells the system what interpreter to pass that file to for execution; in our case the interpreter is Node.js.  After that, the code is fairly straightforward.  It requires the <code>node-emoji</code> module and validates <code>process.argv[2]</code>, which is the first argument placed by the user. By default <code>process.argv[0]</code> is the path for Node.js binary, and <code>process.argv[1]</code> is the path for the script being executed.</p>\n<p>After adding this code, our command is ready to be executed; you can get a 'Hello world!' in your console by running:</p>\n<pre><code>$ node index.js world\n</code></pre>\n<p>If you want to run it using the command specified at the bin section of our <code>package.json</code>, you’ll need to install the package globally from npm.  But just for development purposes to run it locally we can use:</p>\n<pre><code>$ npm link\n</code></pre>\n<p>After executing this command, you can try to execute:</p>\n<pre><code>$  hello-emoji world\n</code></pre>\n<h2>Arguments parsing</h2>\n<p>After examining the code we just wrote, you’ll likely realize that the main issue when writing this kind of application is to control the user's input parsing the arguments included in the command execution. Fortunately, the npm ecosystem offers plenty of choices to solve this problem.</p>\n<p>Here are some modules helping you to parse user-entered arguments. Some even provide some guidelines to structure your CLI's code:</p>\n<ul>\n<li>Yargs: <a href=\"https://www.npmjs.com/package/yargs\">https://www.npmjs.com/package/yargs</a></li>\n<li>Minimist: <a href=\"https://www.npmjs.com/package/minimist\">https://www.npmjs.com/package/minimist</a></li>\n<li>Commander: <a href=\"https://www.npmjs.com/package/commander\">https://www.npmjs.com/package/commander</a></li>\n<li>Args: <a href=\"https://www.npmjs.com/package/args\">https://www.npmjs.com/package/args</a></li>\n</ul>\n<p>These packages allow you to create a CLI supporting multiple operations and include parameters; you could efficiently structure something for our CLI to do things like:</p>\n<pre><code>$ hello-emoji --name=world --json\n</code></pre>\n<p>Printing a JSON object with our greeting</p>\n<pre><code>$ hello-emoji --name=world --emoji=coffee\n</code></pre>\n<p>Instead of a random emoji, this one prints the coffee emoji</p>\n<p>Here is an example implementing minimist to do the parsing to execute commands like the ones above:</p>\n<pre><code class=\"language-javascript\">#!/usr/bin/env node\n\n'use strict'\n\nconst emojis = require('node-emoji')\nconst minimist = require('minimist')\nconst opts = minimist(process.argv.slice(2))\n\nconst emoji = opts.emoji ? emojis.get(opts.emoji) : emojis.random().emoji\n\nif (!opts.name) {\n  console.error(`${emojis.get('no_entry')} Please add your name to say hello using the '--name=' parameter`)\n  process.exit(1)\n}\n\nif (!emojis.has(opts.emoji)) {\n  console.error(`${opts.emoji} is not a valid emoji, please check https://www.webfx.com/tools/emoji-cheat-sheet/`)\n  process.exit(1)\n}\n\nconst greeting = `${emoji}  Hello ${opts.name}!`\n\nif (opts.json) {\n  console.log(JSON.stringify({greeting}))\n} else {\n  console.log(greeting)\n}\n</code></pre>\n<h2>Going interactive</h2>\n<p>So far, we have been working with information coming from the command execution. However, there is also another way to help make your CLI more interactive and request information at execution time. These modules can help to create a better experience for the user:</p>\n<ul>\n<li>Inquirer: <a href=\"https://www.npmjs.com/package/inquirer\">https://www.npmjs.com/package/inquirer</a></li>\n<li>Prompts: <a href=\"https://www.npmjs.com/package/prompts\">https://www.npmjs.com/package/prompts</a></li>\n<li>Prompt: <a href=\"https://www.npmjs.com/package/prompt\">https://www.npmjs.com/package/prompt</a></li>\n<li>Enquirer: <a href=\"https://www.npmjs.com/package/enquirer\">https://www.npmjs.com/package/enquirer</a></li>\n</ul>\n<p>With a package like the ones above, you could ask the user directly to input the desired information in many different styles. The example below is using <code>inquirer</code> to ask the users for the name if it was not included as an argument. It also validates the emoji and requests a new one if the input is not valid.</p>\n<pre><code class=\"language-javascript\">#!/usr/bin/env node\n\n'use strict'\n\nconst emojis = require('node-emoji')\nconst inquirer = require('inquirer')\nconst minimist = require('minimist')\nconst opts = minimist(process.argv.slice(2))\n\nlet emoji = opts.emoji ? emojis.get(opts.emoji) : emojis.random().emoji\n\nasync function main () {\n  if (!opts.name) {\n    const askName = await inquirer.prompt([{\n    type: 'input',\n    name: 'name',\n    message: `Please tell us your name: `,\n    default: () => 'world',\n    validate: (answer) => answer.length >= 2\n    }])\n\n    opts.name = askName.name\n  }\n\n  if (opts.emoji &#x26;&#x26; !emojis.hasEmoji(opts.emoji)) {\n    console.error(`${opts.emoji} is not a valid emoji, please check https://www.webfx.com/tools/emoji-cheat-sheet/`)\n    const askEmoji = await inquirer.prompt([{\n    type: 'input',\n    name: 'emoji',\n    message: `Please input a valid emoji: `,\n    default: () => 'earth_americas',\n    validate: (emoji) => emojis.hasEmoji(emoji)\n    }])\n\n    emoji = emojis.get(askEmoji.emoji)\n  }\n\n  const greeting = `${emoji}  Hello ${opts.name}!`\n\n  if (opts.json) {\n    console.log(JSON.stringify({\n    greeting\n    }))\n  } else {\n    console.log(greeting)\n  }\n}\n\nmain()\n</code></pre>\n<h2>Adding some Eye Candy</h2>\n<p>Even if the interface for this kind of application is reduced to what you can have in a shell, it does not mean that the UI should look bad. There are plenty of tools that can help make your apps look good; here are some different libraries that will add  a nice touch to the look of your CLI output:</p>\n<ul>\n<li><a href=\"https://www.npmjs.com/package/chalk\">Chalk</a> or  <a href=\"https://www.npmjs.com/package/colors\">Colors</a> will allow you to set the color of your text. </li>\n<li>To include images translated to ASCII art, try <a href=\"https://www.npmjs.com/package/asciify-image\">asciify-image</a> or <a href=\"https://www.npmjs.com/package/ascii-art\">ascii-art</a></li>\n<li>If you have to output much information a well-organized output could be in tables, try <a href=\"https://www.npmjs.com/package/table\">Table</a> or <a href=\"https://www.npmjs.com/package/cli-table\">Cli-table</a></li>\n<li>If your CLI requires processes taking some time, like consuming external APIs, querying databases or even writing files, you can add a cute spinner with <a href=\"https://www.npmjs.com/package/ora\">Ora</a> or <a href=\"https://www.npmjs.com/package/cli-spinner\">Cli-spinner</a>. </li>\n</ul>\n<h2>Conclusion</h2>\n<p>Creating user-friendly, useful and beautiful CLIs is part science and part art. After exploring the basics of creating a CLI tool, you can go and explore a universe of possibilities with the packages available through the npm registry. Hopefully, you’ll soon be creating functional and user-friendly tooling that’s missing from your current inventory thanks to the power of Node.js.</p>"}}}}}}