1. What is CLI
CLI is short for Command Line Interface. The user can type executable instructions at the prompt, and the computer, which usually does not support a mouse, executes them. A lot of CLI is used in front-end development. The most typical ones are create-react-app and vuE-CLI for react and vue respectively. Taking vue-CLI as an example, we create a VUE project like this
Vue create my-app then answers some project-related questions from the command line, and finally generates the corresponding project files based on the answers to the questions. So, we’re going to build our own CLI to customize these operations to help with things like project generation and code checking.
2. Related concepts
2.1 command
The command is the name of the operation. For example, create is the command that creates the project. We can run vue –help to see which commands are available:
Usage: vue <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
create [options] <app-name> create a new project powered by vue-cli-service
add [options] <plugin> [pluginOptions] install a plugin and invoke its generator in an already created project
invoke [options] <plugin> [pluginOptions] invoke the generator of a plugin inan already created project inspect [options] [paths...] inspect the webpack configin a project with vue-cli-service
serve [options] [entry] serve a .js or .vue file in development mode with zero config
build [options] [entry] build a .js or .vue file in production mode with zero config
ui [options] start and open the vue-cli ui
init [options] <template> <app-name> generate a project from a remote template (legacy API, requires @vue/cli-init)
config [options] [value] inspect and modify the config
outdated [options] (experimental) check for outdated vue cli service / plugins
upgrade [options] [plugin-name] (experimental) upgrade vue cli service / plugins
migrate [options] [plugin-name] (experimental) run migrator for an already-installed cli plugin
info print debugging information about your environment
Run vue <command> --help for detailed usage of given command.
Copy the code
2.1 Options Options are commands to configure, such as vue create –help, you can see:
Usage: create [options] <app-name>
create a new project powered by vue-cli-service
Options:
-p, --preset <presetName> Skip prompts and use saved or remote preset
-d, --default Skip prompts and use default preset
-i, --inlinePreset <json> Skip prompts and use inline JSON string as preset
-m, --packageManager <command> Use specified npm client when installing dependencies
-r, --registry <url> Use specified npm registry when installing dependencies (only for npm)
-g, --git [message] Force git initialization with initial commit message
-n, --no-git Skip git initialization
-f, --force Overwrite target directory if it exists
--merge Merge target directory if it exists
-c, --clone Use git clone when fetching remote preset
-x, --proxy <proxyUrl> Use specified proxy when creating project
-b, --bare Scaffold project without beginner instructions
--skipGetStarted Skip displaying "Get started" instructions
-h, --help output usage information
Copy the code
- The name of the configuration option starts with – or —
- parameter
- A value passed to a command as if the command were a function and the value is an argument to the function when it is executed.
- Vue create my-app My-app is the parameter, indicating the project name
3. Start
3.1 Initializing the Project
First, create a new empty folder and initialize the project
$ npm init
Copy the code
3.2 Writing JavaScript Scripts
Write a JavaScript script called index.js:
#! /usr/bin/env node console.log('hello cli');Copy the code
#! /usr/bin/env /usr/bin/env /usr/bin/env /usr/bin/env /usr/bin/env
3.3 modify the package. The json
{
"bin": {
"youzan": "./index.js"
}
}
Copy the code
3.4 npm link
The NPM link is used to establish a connection between a local project and a local NPM module so that module tests can be performed locallynpm link
And then you can executeyouzan
The command
4. Configure cli options
The use of commander.js is recommended
$ yarn add commander --save
Copy the code
program.option('-ig,--initgit', 'init git'); console.log('Options: ', program.opts()); // Get the option valueCopy the code
4.1 First Command
Just like vue create, we need to complete a command to create the project, and we can configure the template and whether or not git is initialized
const { program } = require('commander');
const handleCreate = (params, options) = > {
console.log(params, options);
};
program
.command('create <name> [destination]')
.description('create a project')
.action((name, destination) = > {
handleCreate({ name, destination }, program.opts());
});
program.option('-ig,--initgit'.'init git');
program.parse(process.argv);
Copy the code
-
.command() is used to configure commands and parameters, where <> indicates that parameters are required and [] indicates that parameters are optional.
-
.description() Adds a command description
-
.action() is used to add action functions, and the input arguments are used to configure commands
-
program.parse(process.argv); Process command line arguments
5. User interaction problems
To use Inquirer. Js, click on the documentation github.com/SBoudrias/I… Use this article at blog.csdn.net/qq_26733915…
$ yarn add inquirer --save
Copy the code
const handleCreate = (params, options) = > {
console.log(params, options);
inquirer
// User interaction
.prompt([
{
type: 'input'.name: 'author'.message: 'author name? '
},
{
type: 'list'.name: 'template'.message: 'choose a template'.choices: ['tpl-1'.'tpl-2']
}
])
.then((answers) = > {
// Generate project files based on the answers and options and parametersgenFiles({ ... answers, ... params, ... options }); }) .catch((error) = > {
console.error(error);
});
};
Copy the code
6. Generate project files on demand
Create the Templates directory in your project to hold the template files
+-- templates
| +-- tpl-1
| +-- package.json
| +-- tpl-2
| +-- package.json
Copy the code
Then, copy the file to the specified directory.
Using Metalsmith, you can easily copy files to a specified directory or create a new directory if the specified directory does not exist
// Get the path where the command is run
const getCwd = () = > process.cwd();
const genFiles = (options) = > {
// Template directory
const templateSrc = path.resolve(__dirname, `./templates/${options.template}`);
// The project specifies the build directory. If there is no configuration directory in the command, a new directory with the name of the project will be generated in the directory where the current command is run
const destination = options.destination
? path.resolve(options.destination)
: path.resolve(getCwd(), options.name);
Metalsmith(__dirname)
.source(templateSrc)
.destination(destination)
.build((err) = > {
if (err) {
console.error(err); }}); }; .source() and.destination() configure the source and destination directories for replication respectively. Absolute paths are preferredCopy the code
7. Dynamically render the target file
The name and author equivalents in the generated package.json are fixed and should vary with the project name. So package.json must be a template file that is rendered as an object file according to the actual situation while being generated;
7.1 Template uses EJS
yarn add ejs --save
Copy the code
7.2 Modifying template Files
Add handlers between.destination() and.build()
const ejs = require('ejs'); Const renderPathList = ['package.json', // 'SRC /main.js', ] Metalsmith(__dirname) .source(templateSrc) .destination(destination) .use((files) => { If (renderPathList.includes(key)) {const file = files[key]; // const STR = file.contents. ToString (); // const newContents = ejs.render(STR, options); File.contents = buffer.from (newContents); }}); }) .build((err) => { if (err) { console.error(err); }});Copy the code
This way, with a simple CLI, more commands can be added themselves.
8. Command line wait optimization
If the command execution is time-consuming, a friendly prompt to wait is also necessary. Ora can help you
Const genFiles = ()=>{// todo generates files on top... } const ora = require('ora') const processGenFiles = ora('Create project... ') processGenfiles.start () // The progress bar starts to await genFiles(answers); processGenFiles.succeed(`Create project complete: i18n-b-${name}`)Copy the code
9. Git template download
Most CLI tool templates are not locally available, but are downloaded from the Internet. You can use the download-git-repo library as well as the Github API
const { promisify } = require('util')
const clone = async function (repo, desc) {
const download = promisify(require('download-git-repo')) // download-git-repo: Download and extract a git repository (GitHub, GitLab, Bitbucket)
const ora = require('ora')
const process = ora(` download...${repo}`)
process.start() // Progress bar starts
await download(repo, desc)
// download-git-repo Specifies the download method for the export. The first parameter repo is the repository address.
// GitHub - github:owner/name or simply owner/name
// GitLab - gitlab:owner/name
// Bitbucket - bitbucket:owner/name
process.succeed()
}
await clone('[email protected]:sz-web/i18n-b-dashboard.git', name)
Copy the code
10. Execute shell in Node.js (NPM install as an example)
Shell execution in Node.js typically uses the spawn of child_process to stream output from the main process to the child process
const spawn = async(... args) => {const { spawn } = require('child_process')
return new Promise(resolve= > {
constproc = spawn(... args)// Shell spawn is used in node.js to spawn the output stream from the main process to the child process
proc.stdout.pipe(process.stdout) // The normal flow of the child overlaps the normal flow of the main process
proc.stderr.pipe(process.stderr) // The child error stream is inserted into the main process error stream
proc.on('close'.() = > {
resolve()
})
})
}
await spawn('npm'['install'] and {cwd: `. / ` }) // CWD Specifies the directory where the command is executed
Copy the code
11. Package distribution
11.1 npm init
I did it above and I don’t have to do it again
11.2 npm login
- www.npmjs.com Set up an account
- Go to your project root directory and run NPM login
- Enter your username, password and email address
11.2 npm publish
After login, execute NPM publish and publish successfully
12. Use your own NPM package
For example,
- Global installation
NPM install -g/NPM install -g/NPM installCopy the code
- The command
youzan --version
youzan --help
youzan init <project-name>
Copy the code
Further reading
- Build your own CLI zhuanlan.zhihu.com/p/242656395
The last
- A lot of likes will make you look good
- Leave a lot of messages and you’ll get rich