Writing in the front

I recently took on a task – to develop an in-house CLI tool using NodeJS, which is simply a one-line command to quickly structure a project, or to import different files using different commands.

To understand

First, based on the Node environment, then we need to know what cli is. Cli is short for command line interface. Vue-cli, create-react-app, and Express-Generator are all CLI tools.

review

Create an exercise-cli directory and use CMD to enter it:

mkdir exercise-cli && cd exercise-cli
Copy the code

Create index.js under this directory:

//index.js
console.log('Thank you. I'm in America. I just got off the plane. ');
Copy the code

Run index.js with node:

The ignition

Create package.json using NPM init, press Enter, you can also configure the related information, you can choose your own:

package.json

{
  "name": "exercise-cli"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": ""."license": "ISC"
}
Copy the code

Now add the field bin to package.json to store an executable file, which in our case is index.js, so the configuration is as follows:

"bin": {"exercise-cli":"./index.js"
},
Copy the code

Now we configure the exercise-cli command to execute the index.js file. We need to add #! To the header of the index.js file. /usr/bin/env node, let the system find the node’s implementation. As to this plaything specific what, Baidu gives such a thing, can consult by oneself.

//index.js
#! /usr/bin/env node
console.log('Thank you. I'm in America. I just got off the plane. ');
Copy the code

Then enter NPN link or NPM install -g on CMD to install the current project into the global environment, so you can run the file directly using exercise-cli:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"."exercise":"exercise-cli"
 }
Copy the code

NPM run exercise (vUE – CLI) NPM run dev (vUE – CLI) NPM run build (vUE – CLI)

Take off

That’s a bit of a look. Let’s look at how it generates project templates. One idea is to save the project templates in a templates folder, create the project directory with fs.mkdir(), and then copy the files from the templates folder into the project. The local Templates directory looks like this:

1. Copy files

Simulation scenario: Copy vue.min.js from local templates to a newly generated project template. Copy vue.min.js from templates to the new js directory using the copyTemplate() method:

//index.js
#! /usr/bin/env node

var fs = require('fs');
var path = require('path'); // Copy the filefunction copyTemplate (from, to) {
  from = path.join(__dirname, 'templates', from);
  console.log(from);
  write(to, fs.readFileSync(from, 'utf-8'))}functionWrite (path, STR, mode) {fs.writeFileSync(path, STR)} // Create a directoryfunction mkdir (path, fn) {
  fs.mkdir(path, function (err) {
    fn && fn()
  })
}

var PATH = ".";
mkdir(PATH+'/public'.function(){
	mkdir(PATH + '/public/js'.function () {
		copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js'); })})Copy the code

Open any folder with CMD and type exercise-cli. This folder will be public\js\vue.min.js:

2. Copy the folder

We’ve learned how to copy files, but what if I want to copy the entire JS directory in templates into a newly generated project template? If there is a need, there is a solution. We can traverse the entire folder and judge the path traversed to it. If it is a file, we can copy it directly; if it is a folder, we can recurse:

//index.js // Copy directory var copy=function(src,dst){
    letpaths = fs.readdirSync(src); // Read the current directory synchronously (only absolute paths can be read, relative paths cannot be obtained)function(path){
        var _src=src+'/'+path;
        var _dst=dst+'/'+path;
        fs.stat(_src,function(err,stats){//stats This object contains file attributesif(err)throw err;
            if(stats.isfile ()){// Copy if it is a fileletreadable=fs.createReadStream(_src); // Create a read streamletwritable=fs.createWriteStream(_dst); // Create the readable.pipe(writable) stream; }else if(stats.isdirectory ()){// checkDirectory(_src,_dst,copy); }}); }); } var checkDirectory=function(src,dst,callback){
    fs.access(dst, fs.constants.F_OK, (err) => {
        if(err){
            fs.mkdirSync(dst);
            callback(src,dst);
        }else{ callback(src,dst); }}); }; mkdir(PATH+'/public'.function(){
	mkdir(PATH + '/public/js'.function () {
		checkDirectory('C: / Users/Administrator/Desktop/vue - 3.0 / nodeTest/exercise/templates/js',PATH+'/public/js',copy); })})Copy the code

Go to CMD and type exercise-cli. This will generate the public directory, which will generate the entire JS file under templates:

3. Receive command line parameters

We usually use the parameters when using the command line tools, such as webpack -p, Express-e, etc. Here we configure -l for exercise-cli and add layerJS when using exercise-cli -l.

Argv is an array of arguments. The first item is the absolute path to Node.exe and the second item is the absolute path to js execution. Process.argv. slice(2) is used to obtain the input parameter array.

//index.js
console.log(process.argv);
Copy the code

var config = {};
process.argv.slice(2).forEach(item=>{
	if(item=="-l"){
		config.layer = true;
	}
})
var PATH = ".";
mkdir(PATH+'/public'.function(){
	mkdir(PATH + '/public/js'.function () {
		// copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js');
		checkDirectory('C: / Users/Administrator/Desktop/vue - 3.0 / nodeTest/exercise/templates/js',PATH+'/public/js',copy);
		if(config.layer){
			checkDirectory('C:/Users/Administrator/Desktop/exercise-cli/templates/layer',PATH+'/public/js',copy); // Notice the path where layerJS is stored in templates. } }) }) console.log('Copy successful');
Copy the code

LayerJS: layerJS: layerJS: layerJS: layerJS: layerJS

To speed up

The initial commander. Js

There is a tool kit in Node that can be used to quickly develop command-line tools, commander. Js.

First global installation:

npm install commander -g
Copy the code

Here’s an example:

var program = require('commander');
program
    .version('1.0.0'.'-v, --version')
    .command('check [checkname]')
    .alias('c')
    .description('yo yo check now')
    .option('-a, --name [moduleName]'.'Module name')
    .action((checkname,option) => {
        console.log('install' checkname: '+ checkname); console.log(option); }) // Customize the help message. On ('--help'.function() {
        console.log('Let me just say this casually :')
        console.log(' ')
        console.log('How bold the man is, how big the sow is, I love xx')
        console.log('There is much to be done in the wide world, gung ~')
    })
program.parse(process.argv)
Copy the code

Command line execution:

  • Version – Defines the version number of the command program,.version(‘0.0.1’, ‘-v, –version’). The version number of the first parameter is required, and the second parameter can be omitted. The default values are -v and –version
  • Command – Defines a command line directive, followed by a name separated by a space, such as.command(‘app [name]’)
  • Alias – Defining a shorter command line instruction such as executing the command $exercise-cli cis equivalent
  • Description – Description, which will be shown in help
  • Option – Defines parameters. It accepts four parameters, in the first parameter, and it can enter a short name – a long name – the name, use | or separated, when used in the command line, the two are equivalent, the difference is that the latter can be in the program through the callback is available; The second is the description, which will be displayed in the help message; The third parameter is the callback function, which takes a string as an argument. Sometimes we need a command line to create multiple modules, so we need a callback. The fourth parameter is the default value
  • Action – Registers a callback function. Note that the callback does not currently support let declarations
  • Parse – Used to parse process.argv, set options, and trigger commands. Examples:.parse(process.argv)

This gives you a general idea of how to write a command line tool. Do it yourself: complete paragraph 3 with commander.js. Receive examples in command line arguments.


Dividing line (the deeper and shallower parts below are updated on April 30, 2019)

In-depth inquirer. Js

When we create scaffolding, we’ll find that a lot of scaffolding requires frequent interaction with the command line, just as we did when we started using NPM init. So how do we do that? This is where Inquirer. Js comes in.

Var inquirer = require(var inquirer = require('inquirer');
Copy the code
  1. The basic grammar
var inquirer = require('inquirer');
inquirer.prompt([/* Pass your questions in here */]).then(function (answers) {
    // Use user feedback for... whatever!! 
})
Copy the code
  1. Parameters,
  • Type: Indicates the type of the query. The options are input, confirm, list, rawlist, expand, checkbox, password, and editor.
  • Name: the variable that stores the current question answer;
  • Message: a description of the problem;
  • Default: the default value.
  • Choices: list options, available under certain types, and containing a separator;
  • Validate: verifies the user’s answer;
  • Filter: The user answers are filtered and the processed value is returned.
  • Transformer: Process the display of the user’s answers (e.g. change the font or background color) without affecting the content of the final answer;
  • When: Judge whether the current question needs to be answered based on the answers to the previous questions.
  • PageSize: Changes the number of rendered lines for certain types;
  • Prefix: Modify the default message prefix.
  • Suffix: Change the default message suffix.
  1. The example analysis

In the.action callback, type the following:

Var prompList = [{var prompList = [{type:'input',
		message:'name',
		name:'name'}, {type:'input',
		message:'Mobile phone Number',
		name:'phone',
		validate:val=>{
			if(val.match(/\d{11}/g)){
				return true
			}
			return 'Please enter 11 digits'
		}
	},{
		type:'confirm',
		message:'Whether to participate in this assessment? ',
		name:'assess',
		prefix:'the prefix'}, {type:'confirm',
		message:'Do you agree with the assessment instructions? ',
		name:'notice',
		suffix:'the suffix',
		when:answers=>{
			return answers.assess
		}
	},{
		type:'list',
		message:'Welcome to this examination, please select education:',
		name:'eductionBg',
		choices:[
			"College"."Undergraduate"."Bachelor degree or above"], filter:val=>{// Add degree after the selected contentreturn val+'degree'
		}
	},{
		type:'rawlist',
		message:'Please choose your favorite game:',
		name:'game',
		choices:[
			"LOL"."DOTA"."PUBG"] {},type:'expand',
			message:'Please choose the fruit you like:',
			name:'fruit',
			choices: [
			{
				key: "a",
				name: "Apple",
				value: "apple"
			},
			{
				key: "O",
				name: "Orange",
				value: "orange"
			},
			{
				key: "p",
				name: "Pear",
				value: "pear"}]}, {type:'checkbox',
		message:'Please choose your favorite color:',
		name:'color',
		choices:[
			{
				name: "red"}, new inquire.separator (), // Add Separator {name:"blur",
				checked: true}, {name:"green"
			},
			new inquirer.Separator("-- delimiter --"), // Custom delimiter {name:"yellow"}]}, {type:'password',
		message:'Please enter your game password:',
		name:'pwd'
	}
	
]
inquirer.prompt(prompList).then(answers=>{
	console.log(answers);
})
Copy the code

The command line interaction is as follows:

Shallow the chalk. Js

Finally, we introduce Chalk to beautify the command line, which is lightweight, high performance and low learning cost. Continue with the example above by introducing Chalk to output:

Var chalk = require(var chalk = require('chalk');
Copy the code

Print the following in inquirer:

inquirer.prompt(prompList).then(answers=>{
	console.log(answers);
	console.log(chalk.green('Assessment completed')// font green console.log(chalk. Blue ('You're the best.'Console. log(chalk. Blue. BgRed (chalk.'May Day holiday') // Support setting background console.log(chalk. Blue (answers))})Copy the code

The following information is displayed:

landing

To get others to install your CLI tool, you need to publish it to NPM. First create an account on NPM website (note that email verification is required), type NPM adduser in the command line, and then fill in your username, password, and email. Then type NPM publish:

npm install -g exercise-cli
npm install exercise-cli

Code has been uploaded toMy lotWelcome Fork.

Thank you

  • Follow the old driver around the command line
  • Write cli tools with Node
  • Build your own scaffolding tools with commander. Js