CLI实践与应用

179 阅读1分钟

背景

在工作中新开一个项目会有很多重复的配置需要逐一添加,比如菜单权限,选项卡权限,页面权限,拖拽,api代理拦截器,统一样式,定制化样式等,因此想自己建立一个生成模板的脚手架工具,以模板为基础构建对应的项目,而目前前端主要是使用vue,react,所以分成两套模板,这样的话,如果新开始一个项目的前期工作将会事半功倍。

依赖

"dependencies": {
    "commander": "^3.0.1", //将文字输出到终端当中
    "async": "^2.6.1", 
    "chalk": "^2.4.1", //终端字体颜色
    "consolidate": "^0.15.1",//模板引擎整合库
    "download-git-repo": "^1.0.2",//现在github中的模板
    "handlebars": "^4.0.11", //模板编译器
    "inquirer": "^6.0.0", //命令行的回答的模块
    "metalsmith": "^2.3.0",//静态网站的生成库
    "ora": "^3.0.0", //终端里有显示载入动画 
    "request": "^2.87.0", //请求
    "rimraf": "^2.6.2", //使用 UNIX 命令 rm -rf的模块
    "user-home": "^2.0.0"// 获取用户主目录的路径
    ...
  }

流程

  1. 拉取模板信息
  2. 选择模板
  3. 判断本地是否存在模板: 存在则选择是否覆盖(覆盖则删除原有模板从新下载生成)否则直接生成,本地不存在则下载并生成
  4. 选择下载的分支
  5. 输入项目名称 项目生成地址
  6. 结束-开始编码

部分代码详解

拉取模板列表

 const spinner = ora('fetching template list...')
 spinner.start()
 request({
   uri:'http://47.98.120.163:8080/list.json',
   timeout:5000
 },(err, response, body)=>{
   if(err) {
     spinner.fail(chalk.red('fetch template list unsuccessfully'))
     console.log(err)
   }
   if(response&&response.statusCode===200){
     spinner.succeed(chalk.green('fetch template list successfully'))
     callback(JSON.parse(body));
   }
 })

下载模板

    function downloadAndGenerate(tmpRepo,tmpName,tmpUrl){
    const spinner=ora('downloading template...')
    const tmpDest=path.join(tmpRepo,tmpName)
    inquirer.prompt([{
      type:'input',
      name:'branch',
      message:`the name of branch you need in ${tmpName}`,
      default:'master'
    }]).then(answer=>{
      spinner.start()
      download(`${tmpUrl}#${answer.branch}`,tmpDest,{
        clone:false
      },(err)=>{
        if(err){
          spinner.fail(chalk.red('download template unsuccessfully'))
          console.log(err)
        }else{
          spinner.succeed(chalk.green('download template successfully'))
          generate(tmpDest)
        }
      })
    })
  }

生成模板

const metalsmith=Metalsmith(tmpPath)
  inquirer.prompt([{
    type:'input',
    name:'name',
    message:'The name of project',
    default:'swy-fe'
  },{
    type:'input',
    name:'destination',
    message:'The destination of project',
    default:process.cwd()
  }]).then(answer=>{
    //项目生成路径
    const destination=path.join(transformIntoAbsolutePath(answer.destination),answer.name)
    const spinner = ora('generating...').start()
    //加入新的全局变量
    Object.assign(metalsmith.metadata(),answer)
    
    spinner.start()

    metalsmith
    .source('.')
    .destination(destination)
    .clean(false)
    .build(function(err) {      
      spinner.stop()
      if (err) throw err
      console.log()
      console.log(chalk.green('Build Successfully'))
      console.log()
      console.log((`${chalk.green('Please cd')} ${destination} ${chalk.green('to start your coding')}`))
      console.log()
    })
  })