Using vue-CLI as a prototype as a reference, we wrote a CLI by hand
specifications
- Realize human-computer interaction and select configuration as required
- Github template resources automatically download and automatically install
- Implement dependency automatically start template repository after installation
- Implement reduced-form routing: When A page A is added, the page A is automatically added in route configuration and TAB
Depend on the installation
$ yarn add commander inquirer download-git-repo ora handlebars figlet clear chalk open watch -D
Copy the code
- Dependency description:
- Commander Nodejs command configuration tool
- Inquirer A set of commonly used interactive command-line user interfaces.
- Download-git-repo A tool for downloading github files
- Ora is an elegant terminal loader
- Handlebars is a simple template language
- Figlet tool for printing good-looking custom prompts in terminals
- clearThe terminal screen clearing tool functions as Linux commands
clear
And the Windowscls
- Chalk is similar to the terminal’s brush tool and can give logs hints with different color patterns
- Open Automatically opens the browser
- Watch is used to listen for file changes
Initialize the
- New folder:
ddb
- Go to the folder and use
npm
Initialization:npm init -y
- New related file:
- new
/bin/ddb.js
- new
/lib/init.js
- new
/lib/download.js
- new
lib/refresh.js
- new
- configuration
package.json
"name": "ddb"."bin": {
"ddb": "./bin/ddb.js"
},
Copy the code
- Binding soft connection:
npm link
If there is an error here, it could be"./bin/ddb"
without.js
The suffix
Now that the configuration is complete, it’s time to start writing code
Hello,World
So step one, let’s say Hello World
- in
/bin/ddb.js
The code is as follows
#! /usr/bin/env node
'use strict';
const program = require('commander')
program
.version('0.0.1')
.parse(process.argv);
Copy the code
-
Enter the command DDB -v on the terminal to check whether the corresponding version number is displayed. If yes, it indicates that the previous configuration is successful
-
Write /lib/init.js as follows:
const figlet = promisify(require('figlet'))
const clear = require('clear')
module.exports = async name => {
clear()
figlet('Hello World!! '.function(err, data) {
if (err) {
console.log('Something went wrong... ');
console.dir(err);
return;
}
console.log(data)
})
}
Copy the code
- Modify the
/bin/ddb.js
code
#! /usr/bin/env node
'use strict';
const program = require('commander')
program
.version('0.0.1')
.parse(process.argv);
program
.command("init <name>")
.description("init project")
.action(require('.. /lib/init'))
program.parse(process.argv)
Copy the code
- Test, enter command in terminal
ddb init test
We can see that the terminal output is very largeHello, world
With the words
ddb create
Next, we start writing the DDB create command
- Before you start, you might want to read about inquirer, click I read
- To prepare
/lib/quesiton.js
file
const question = [
{
name:'conf'./* key */
type:'confirm'.Confirm * / / *
message:'Do you want to create a new project? ' / * hint * /}, {name:'name'.message:'Please enter a project name? '.when: res= > Boolean(res.conf) /* Whether to perform */}, {name:'author'.message:'Please enter author? '.when: res= > Boolean(res.conf)
},{
type: 'list'./* Select box */
message: 'Please select Public Administration status? '.name: 'state'.choices: ['mobx'.'redux']./ * option * /
filter: function(val) { Filter / * * /
return val.toLowerCase()
},
when: res= > Boolean(res.conf)
}
]
module.exports = question
Copy the code
- write
/bin/init.js
file
#! /usr/bin/env node
'use strict';
const program = require('commander')
const inquirer = require('inquirer')
const chalk = require('chalk')
const question = require('.. /lib/question')
program
.version('0.0.1')
.parse(process.argv);
program
.command("create <name>")
.description("create a project")
.action(() = > {
chalk.green("-_ -... Welcome to use DDB-CLI to easily build vuE-CLI applications.")
// Human-computer interaction, see question file for details
inquirer.prompt(question).then((answer) = > {
if (answer.conf) {
console.log('answer', answer);
}
})
})
program.parse(process.argv)
Copy the code
- Execute commands to test:
ddb create testaa
The next step is to enter the interactive selection configuration interface, and finally, all the configurations will be printed out
There are two ways to implement template files. One is to put the template in the CLI and copy it directly during installation to modify some configuration information. The second option is to put the template in a remote repository, download it remotely each time you create a project, and write some configuration information. Here, we take the second option
-
Next, we start writing the create method, which includes the following features
- Download the selected template
Edit the template information in the file, as shown inpackage.json
- Install dependencies for this template
- Automatically open browser preview after installing dependencies
-
Download the selected template and compile the /lib/download.js file
module.exports.clone = async function (repo, desc) {
const { promisify } = require('util')
const download = promisify(require('download-git-repo'));
const ora = require('ora')
const process = ora('Downloading...${repo}`)
process.start()
await download(repo, desc)
process.succeed()
}
Copy the code
- Modify the
/lib/create.js
file
const { clone: download } = require('./download')
const chalk = require('chalk')
const log = content= > console.log(chalk.green(content))
module.exports = async function (answer = {}) {
if (!Object.keys(answer)) return
const { name = 'test', author = 'Tom', template = 'vue-template'} = answer
const templateMap = {
'vue-template': 'github:su37josephxia/vue-template'.'react-template': 'github:https:NLRX-WJC/react-antd-admin-template'
}
const downloadUrl = templateMap[template]
log('Create project:${name}`)
await download(downloadUrl, name)
}
Copy the code
- The next step is to install a dependency on the downloaded file template, which is still edited
/lib/create.js
const { clone: download } = require('./download')
const chalk = require('chalk')
const log = content= > console.log(chalk.green(content))
module.exports = async function (answer = {}) {
if (!Object.keys(answer)) return
const { name = 'test', author = 'Tom', template = 'vue-template'} = answer
const templateMap = {
'vue-template': 'github:su37josephxia/vue-template'.'react-template': 'github:https:NLRX-WJC/react-antd-admin-template'
}
const downloadUrl = templateMap[template]
log('Create project:${name}`)
await download(downloadUrl, name)
InstallDev(name)
}
// Start the child process for dependency installation
const spawn = async(... args) => {const { spawn } = require('child_process')
return new Promise(resolve= > {
constproc = spawn(... args) proc.stdout.pipe(process.stdout) proc.stderr.pipe(process.stderr) proc.on('close'.() = > {
resolve()
})
})
}
const InstallDev = async (name) => {
// Automatically install dependencies - use child processes to do so
log('===== Installation dependency =====')
await spawn('yarn'['install'] and {cwd: `. /${name}`})
log('===== Installation completed ===== ===== Startup mode ===== CD${name}
npm run serve
or
yarn serve
`)
Copy the code
- Test, execute
ddb create
, we found that after downloading template, it automatically entered the folder for dependency installation - Next, we implement automatic open browser and start project, edit
/lib/create.js
const open = require('open')
// ...
const openAndStart = async (name) => {
// Automatically open the browser
open('http://localhost:8080')
/ / start
await spawn('yarn'['serve'] and {cwd: `. /${name}`})}Copy the code
Now that we have implemented the above requirements, let’s implement the routing contract configuration
The reduced-form route is configured
In the vUE development process, we have one operation that must be repeated, we can use the command to implement:
- Add a page
- Configuring Routing Information
- Other pages add this new page
Let’s take a simple example
- new
/lib/refresh.js
, the code is:
const fs = require('fs')
// For template compilation
const handlebars = require('handlebars')
module.exports = async() = > {// Get the list
const list = fs.readdirSync('/src/views')
.filter(v= >v ! = ='Home.vue')
.map(item= > ({
name: item.replace('.vue'.' ').toLowerCase(),
file: item
}))
// Generate a route definition
compile({list}, '/router.js'.'/template/router.js.hbs')
// Generate a menu
compile({list}, '/src/App.vue'.'/template/App.vue.hbs')
/** * Template compilation *@param {*} Meta Data definition *@param {*} FilePath Target file *@param {*} TemplatePath template file */
function compile(meta, filePath, templatePath) {
if (fs.existsSync(templatePath)) {
const content = fs.readFileSync(templatePath).toString()
const result = handlebars.compile(content)(meta)
fs.writeFileSync(filePath, result)
console.log(`${filePath}Create success ')}}}Copy the code
- in
/lib/create.js
join
program
.command("refresh")
.description("refresh routers and menu")
.action(require('.. /lib/refresh'))
Copy the code
-
Testing:
- in
Template file/SRC /views/
Creating a DirectoryTest.vue
, the content of
<template> <div class="test"> <h1>This is an Test page</h1> </div> </template> Copy the code
- perform
ddb refresh
After, you can see the success prompt, viewTemplate file/SRC/Phones.js
和Template file/SRC/app.vue
, you can see the newTest
Associated routes and tabs - interface
localhost:8080
You can also see the corresponding effect
- in
At this point, the CLI is done by hand
conclusion
- We mainly use
commander
Define the nodeJS terminal command, and then useinquirer
Realize interaction with command interface - Then use the beautification tool
figlet
Write ASCII style welcome interface field, usechalk
Tools to beautify command prompts - Then use the
promisify
Wrapping asynchronous operations returns a promise, useddownload-git-repo
Code download - Use the built-in NodeJS
child_process
Child process to perform installation dependency tasks, usingopen
Open up our template project - And, using
fs
Read and write modules, combinedhandlebars
Tool to achieve automatic configuration of files, so as to achieve the effect of reduced-form routing
Above, our handwritten CLI learning comes to an end, more information, please read the following resources, write more practice, you will be able to write a better use of the CLI ~
Code: DDB – cli
References:
- How-to-build-a-cli-with-node-js recommended!!
- command-line-app-with-nodejs
- Node.js command-line program development tutorial – Ruan Yifeng
- How to develop a Node.js command-line (CLI) tool recommendation from scratch
- Create CLI recommendations using Node.js
- Open the class teacher Xia – CLI code information
- Develop a Node command-line tool from scratch
- Write command line tools -JavaScript,NodeJs
- Customize CLI tools
- This is a combination of crawler and Node command line tools, awesome!
- Video tutorial – Complete a CLI tool with Node from 0 to 1
- terminal-node-todo