[web] 从零制作一个cli脚手架

244 阅读2分钟

通过该文章你可以获取什么?

  1. 能够实现 命令行交互小项目
  2. 通过命令行实现一个 cli脚手架项目:
    • 包括项目模板的快速创建
    • git模板仓库的拉取创建等
    • 自定义代码模板,命令快速创建

一、初始化项目

  1. node init 或者 yarn init 新建一个项目。
  2. 新建脚本目录,创建脚本入口文件。这边以(bin/main.js)举例。
  3. 脚本文件中首行写入: #!/usr/bin/env node,代表脚本运行在node环境

image.png 4. pakeage绑定脚本: 。 image.png

  1. 在项目目录通过sudo npm link建立项目链接。取消链接使用 npm unlink [package.json中的name]

至此,我们实现了通过命令行调用项目中的脚本。

我们可以在bin/main.js,加入console.log("我的第一个Cli脚本")。然后在通过cmd命令调用my-cli进行验证。


二、引入开发依赖

我们需要的开发依赖主要如下:

  1. commander : *命令行操作相关。
  2. shelljs : *调用执行shell。
  3. inquirer : *交互式问答 cmd 工具。
  4. git-clone : 可选,用于clone git模板仓库。
  5. tracer : 可选,更好看的console输出,带颜色。
  6. fs-extra: 可选,操作文件。
//package.json
{
  "name": "your-cli",
  "version": "1.0.0",
  "main": "index.js",
  "author": "maguangcan",
  "bin": {
    "my-cli": "./bin/main.js"
  },
  "devDependencies": {
    "commander": "^8.3.0",
    "git-clone": "^0.2.0",
    "shelljs": "^0.8.5",
    "tracer": "^1.1.5",
    "fs-extra": "^10.0.0",
    "inquirer": "^8.2.0"
  }
}

三、定义创建命令行

接下来我们开始编写创建模板、克隆模板等相关脚本。 新建创建脚本文件: create-project.js 。名字任取。

image.png

main.js 脚本编写

#!/usr/bin/env node
// 第一行命令代表该文件在node环境下运行

const program = require('commander')
const createProject = require('./create-project') //引入外部的我们定义的创建脚本。
// 声明版本信息
program
    .version('1.0.0')
    .description('我的第一个脚手架~')

//声明命令:my-cli create,关联到 create-project.js
// [project] 代表可选参数,可以自行配置。该demo表示项目名。
program.command('create  [project]')
    .action((project) => createProject(project))

program.addHelpText('after', `
    Example call:
    $ create [project] 项目名:非必填
`);

//执行解析
program.parse(process.argv);

设置模板目录

在项目目录中创建目录templates,目录名在create-project中引用,可自行设置。模板目录下,创建自己的模板项目。 下文以MyTemplate举例。

create-project.js 脚本编写

const clone = require('git-clone') //该库用于通过git创建模板,无需该功能的可以不使用
const shell = require('shelljs');
//每一个日志前加入标识
const log = require('tracer').colorConsole({
    format: `CLI=>{{message}}`
})
const fs = require('fs-extra');
const path = require('path');
//问答库
var inquirer = require('inquirer')

log.info('创建例子:my-cli create  [my-project]')

//模板列表:这里设置了三个项目模板
const TemplateList = {
    MyTemplate: "[ ]我的第一个模板",
    Git: "[ ]从GIT获取模板"
}

//获取模板路径
const PWD_PATH = shell.pwd()
const TPL_PATH = path.resolve(__dirname, '../templates')

//拷贝模板到指定目录
async function copyTplDirs(tplName, targetDir) {
    const targetPath = targetDir && targetDir !== '.' ? `${PWD_PATH}/${targetDir}` : `${PWD_PATH}`
    log.info(`正在生成模板代码,生成位置:${PWD_PATH} ...`)
    //创建文件夹
    await fs.promises.access(targetPath)
        .catch(async err => await fs.promises.mkdir(targetPath, { recursive: true }));
    //复制文件
    fs.copy(`${TPL_PATH}/${tplName}`, targetPath, {
        filter: (src) => {
            //TODO 过滤非必要文件夹,处理一些特殊的文件
            return !new RegExp('/node_modules|.git/').test(src)
        }
    }).then(() => {
        log.info('**创建完成...**')
    })
}

//创建项目
module.exports = async function createProject(project) {
    //选择模板问答
    const answerTpl = await inquirer.prompt([{
        type: 'list',
        name: 'template',
        message: '选择创建模板:',
        choices: [TemplateList.MyTemplate, TemplateList.Git]
    }])
    
    switch (answerTpl.template) {
        //内置模板
        case TemplateList.MyTemplate:
            //拷贝文件夹:对应 template/MyTemplate模板目录。
            copyTplDirs('MyTemplate', project)
            break
        //git创建模板    
        case TemplateList.Git:
            //选择模板
            inquirer.prompt([{
                type: 'input',
                name: 'gitUrl',
                message: '请输入git模板地址:',
            }]).then((answers) => {
                // log.info('结果为:' + answers.gitUrl) 
                if (answers.gitUrl) {
                    clone(answers.gitUrl, `${PWD_PATH}/${project}`, null, function () {
                        shell.rm('-rf', `${PWD_PATH}/${project}/.git`)
                        log.info('项目创建完成!')
                    })
                } else {
                    log.error('Git地址异常!')
                }
            })
            break
        default:
            log.warn('**模板开发中...**')
            break;
    }

}

CMD 在任意目录执行命令验证。

my-cli create my-demo

GIT 例子。

GIT: github.com/AlwaysSum/Y…

功能进一步设想

  • 1、在模板文件中定义配置语法,在创建目录读取一个配置文件,根据相关配置进行不同的构建生成。
  • 2、增量更新:对已生成的文件更新,保持现有文件内容,里面新增插入标识。新增时插入到指定标识区间。 ...

See you~~

-3/300-