Developing a command-line tool using Node is fun and much easier than other languages. Today yamatsuki has written an article summarizing how to write a friendly and robust CLI tool.

After reading this article, I highly recommend reading the Node CLI Tool Best Practices article on Github. True to its title, the 2000 star Github article is a best practice.

  • Front-end engineering series
  • Node advanced series
  • Handwritten source code series

Command line tools and environment variable PATH

What is a command line tool?

The initial impression is that the system commands such as LS and PWD can be executed in the terminal. There are many such commands, which are called system built-in commands.

If you use “which” to find out where they came from, you can find out what they are like:

# PWD is a built-in command
$ which pwd
pwd: shell built-in command
Copy the code

As I understand and use Linux/Unix systems, I have discovered many non-built-in commands:

  • top
  • ps
  • netstat
  • dig
  • man

Using which to get to the bottom of it, they actually execute in a bin directory

$ which top
/usr/bin/top

$ which ps
/bin/ps
Copy the code

These bin directories are in the environment variable PATH, and suddenly you see the light. In short: commands for paths in the environment variable PATH can be executed anywhere else.

export PATH=$HOME/bin:/usr/local/bin:$PATH
Copy the code

Speaking of environment variables, you can use env to list all of them.

$ env
LANG=zh_CN.UTF-8
USER=root
LOGNAME=root
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
Copy the code

What do you seem to be thinking about? Fears of being dominated by environment variables when configuring Java in college?

Yes, executable commands for all languages need to be placed under PATH, but installation tools for other languages do this for you automatically, while Java lets you handle it yourself.

  • java
  • python
  • pip
  • node
  • npm

The same goes for developing command lines. Place your command-line tool scripts in the PATH under the environment variable PATH. The goal of this article is to:

Use Javascript, a language familiar to front-end developers, to develop a command-line tool with the help of the Node environment.

The principle of

First look at the command line tools for two nodes:

  • [serve](https://github.com/vercel/serve)A popular static file server, the work of the Vercel team (the next.js team)
  • markdownA mountain moon writes its own parse URL to markdow’s command line. Parse the symbolic links to which they point by command
$ ls -lah $(which serve)
lrwxr-xr-x  1 xiange  admin    65B  7 12  2020 /usr/local/bin/serve -> .. /.. /.. /Users/shanyue/.config/yarn/global/node_modules/.bin/serve $ ls -lah $(which markdown)
lrwxr-xr-x  1 xiange  admin    48B  1 28 20:06 /usr/local/bin/markdown -> .. /lib/node_modules/markdown-read/md-read-cli.jsCopy the code

Here’s how the Node global command line works:

  1. NPM globally downloads a package to a path/usr/local/lib/node_modulesYarn The same path is used~/.config/yarn/global/node_modules)
  2. According to the library’s package.jsonbinField to mount the corresponding command line PATH to the PATH PATH by symbolic index
  3. Add x permissions to the corresponding binary script (executable file permissions)

In short, command line tools in the Node environment rely on nothing more than the environment variable Path and a symbolic link

From the package. The json

The bin field in package.json specifies the name of the final command line tool

{
   "bin": {
    "serve": "./bin/serve.js"}}Copy the code

As shown above, server is the command that is ultimately executed on the terminal, and./bin/serve.js is the script file that is actually executed by the command.

For final executable command-line tools, Node projects tend to place files in the bin directory, as Typescript does with its command-line configuration:

{
  "bin": {
    "tsc": "./bin/tsc"."tsserver": "./bin/tsserver"}},Copy the code

An execution environment

For files that can be executed directly, specify the execution environment and add the following line at the beginning:

#! /usr/bin/env node

// code down
Copy the code

What does this sentence mean?

  1. #!Add an interpreter to indicate the use of the file/usr/bin/env nodeTo perform the
  2. /usr/bin/envIs the absolute PATH to env, used to execute commands in the PATH PATH (node command line location is different in various systems, so useenv nodeFind the path and execute)
  3. env nodeAt the human level, it can be understood as executionnodeThe command

This script is executed using the Node interpreter, and env node is able to locate the node interpreter correctly

// If not written#! /usr/bin/env node$node serve. // If#! The /usr/bin/env node can be executed directly
$ serve .
Copy the code

Parsing command input

In a server application, you can get user input from request.url. queryString and Request.body.

In the command line tool, user input is available via progress.argv. See the following example:

$ node cmd.js 1 2 3
Copy the code
// Output: [
// '/usr/local/bin/node',
// '/Users/shanyue/cmd.js',
/ / '1',
/ / '2',
/ / '3',
// ]
process.argv
Copy the code

Argv can be customized by parsing process.argv to take a variety of arguments as input to the command line. `

Of course, parsing parameters also follows the basic rules of POSIX compatibility: format, optional, required, shorthand, description, help, and so on. The command line tool naming protocol article is detailed enough.

// A more tidy command line help $node --help
Usage: node [options] [ script.js ] [arguments]
       node inspect [options] [ script.js | host:port ] [arguments]

Options:
  -                                         script read from stdin (default if no file name is provided,
                                            interactive mode if a tty)
  --                                        indicate the end of node options
  --abort-on-uncaught-exception             aborting instead of exiting causes a core file to be generated for
                                            analysis
  -c, --check                               syntax check script without executing
  --completion-bash                         print source-able bash completion script
  --cpu-prof                                Start the V8 CPU profiler on start up, and write the CPU profile to
                                            disk before exit. If --cpu-prof-dir is not specified, write the profile
                                            to the current working directory.
Copy the code

Because POSIX is compatible with complex rules, it has derived several libraries about parsing command parameters, standing on the shoulders of giants, in the actual work directly open it!

  • Yargs: Star 8.5K, weekly downloads 4900K
  • Commander: Star 19.7K, weekly downloads 5300K, works of tJ

Here’s a Demo: Use Commander to parse different input commands

const { program } = require('commander')

// Parse different instruction inputs
program
  .option('-d, --debug'.'output extra debugging')
  .option('-s, --small'.'small pizza size')
  .option('-p, --pizza-type <type>'.'flavour of pizza')

program.parse(process.argv)

const options = program.opts()
console.log(options)
Copy the code

User experience with rich colors

This is standard output from the Next Build command line, with colorful highlighting and rich list displays to provide a richer user experience.

Most terminals already support color output, which is controlled by ANSI coding, and have a mature library for color control. Such as ANSI – styles

import styles from 'ansi-styles';

console.log(`${styles.green.open}Hello world!${styles.green.close}`);
Copy the code

Rich highlighting, like code highlighting, allows users to quickly capture key points. The exception, warning, and success messages are color-coded so that the output of the command line tool is easy to see. Most modern build tools, such as Webpack, also support color output.

The following are two of the more advanced color libraries commonly used in command line tools that support the output of a wide variety of colors, although the basic principle is still ANSI encoding.

  • chalk
  • colors

The following example is Chalk, where Error and Warning messages are represented in different colors

const chalk = require('chalk')
 
const error = chalk.bold.red
const warning = chalk.keyword('orange')
 
console.log(error('Error! '))
console.log(warning('Warning! '))
Copy the code

interoperability

On the Web, Input can be used to present colorful forms such as switches, multiple selections, radio selections, Input fields, and so on.

In command line tools, multiple libraries can be borrowed to achieve strong interactivity.

  • enquirer
  • ora
  • ink

Release and Installation

After the hard work of writing a CLI tool, it’s time to test the results. Publishing to the NPM repository enables everyone to use your command-line tools, which is the most important step

NPM login is required to login to NPM registory before publishing
$ npm publish
Copy the code

After the success of the global download command line tool, began to use, using it to grab my blog home page

$ npm i -g markdown-read
/usr/local/bin/markdown -> /usr/local/lib/node_modules/markdown-read/md-read-cli.js
+ [email protected]
added 102 packages from 72 contributors and updated 10 packages inS $33.15 markdown https://shanyue.tech## [#](# Santsuki's trivial blog entry) Santsuki's trivial blog entryThis blog is a summary of some articles about the problems encountered in front end, back end and operation and maintenance in ordinary work. Later will also do a series of articles for output, such as front-end advanced advanced series, personal server guide series. Personal wechat shanyue94, welcome to add communication## [#](# name origin) Name origin
Copy the code

conclusion

This article explains the following aspects from shallow to deep:

  1. What is the principle of a globally executable command line tool
  2. Configuration required to develop a command line tool in Node
  3. How to parse parameters when developing command-line tools

And according to the practice, developed a small tool to read Markdown from THE URL: Markdown -read, welcome Star, download and use.

In addition, I made a Web version based on this command line, welcome to experience: devtool.tech/html-md