自定义脚手架

971 阅读2分钟

背景

拆分出的子工程具备了相同的目录结构,一致的技术栈,为脚手架提供的基础;新创建的子工程,每次都要手动改固定文件文件的配置,搭建脚手架很有必要。换句话,就是人为手动改配置正确率达不到 100%

思路

说简单一些,脚手架是下载模板(clone),改文件内容(手动改),安装启动(install,run)等重复劳动整合,最后通过简单指令让电脑完成上述劳动的一个方法。

stateDiagram-v2

state 开发 {
    执行clone模板-->改文件内容
    改文件内容-->install安装依赖
    install安装依赖-->run启动
}
[*] --> 开发:无脚手架
开发 --> 浏览器
浏览器 --> [*]

state 脚手架{
    自动clone模板-->自动改文件内容
    自动改文件内容 --> 自动install安装
    自动install安装--> 自动run启动
}
[*] --> 新开发:安装脚手架
新开发-->脚手架: 执行脚手架命令
脚手架-->浏览器

通过上述流程对比,使用脚手架命令可以最大限度解放开发,将重复内容交给电脑,保证修改稳定性。

实施

准备工作

简单了解:commander,inquirer,child_process,cmd

  1. commander提供自定义命令
  2. inquirer提供交互方式
  3. child_process提供执行cmd的环境

步骤

  1. npm init初始化package.json,并为脚手架起一个响亮的名字(暂定t-cli),回车到底。

  2. npm install commander inquirer child_process安装t-cli需要用到的包,安装成功后,pacaagek.json内容如下:

    {
      "name": "t-cli",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "child_process": "^1.0.2",
        "commander": "^8.2.0",
        "inquirer": "^8.2.0"
      }
    }
    
    
    
  3. package.json同级目录下,手动创建bin.js作为t-cli的入口,bin.js内容如下:

    #!/usr/bin/env node
    
    const {Command} = require('commander');   //引入commander
    const program = new Command();            //new command实例
    
    //添加版本号为package.json中的版本
    const {version} = require('./package.json'); 
    program.version(version)
    
    //定义使用方式
    program.usage('<command> [options]')
    
    //自定义命令
    program
        .command('init')                    //定义命令init
        .description('初始化项目模板')       //添加命令描述
        .alias('i')                         //给init命令添加别名i,可以i启动init
        .action(async(opt,cmd)=>{                //使用命令init执行的操作
            console.log('实际执行的操作')
        })
    
    //传入环境变量
    program.parse(process.argv)
    
    
  4. node bin.js init或者node bin.js i运行,走到对应的action中表示成功。

    企业微信截图_20211015110931.png

  5. 在package.json中添加bin选项,然后在package.json同级目录使用npm link链接成全局命令

    //package.json
    {
      "name": "t-cli",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "bin": {
        "t-cli":"./bin.js"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "child_process": "^1.0.2",
        "commander": "^8.2.0",
        "inquirer": "^8.2.0"
      }
    }
    
    
  6. 使用t-cli init验证全局指令 企业微信截图_20211015134058.png

  7. 在action的方法中,使用inquirer增加用户交互

    const inquirer = require('inquirer');
    
    //action方法
    let answer = await inquirer.prompt([{
        type: 'list',
        message: '请选择模版:',
        name: 'tplName',
        choices: ['模板1','模板2']
    }, {
        type: 'input',
        message: `请输入模板名称:`,
        name: 'name',
    }]
    console.log(answer);
    

    执行结果:

    企业微信截图_20211015135826.png 企业微信截图_20211015135916.png 企业微信截图_20211015135949.png

  8. 使用child_process,调用git clone下载模板文件。

    const {exec} = reuqire('child_process');
    let bat = exec('git clone http://*********.git',function(error){
        if(error){
            console.log(error)
        }else{
           console.log('done') 
        }
    })
    bat.stdout.on('data', (data) => {
          console.log(data.toString());
    });
    bat.stderr.on('data', (data) => {
         console.log(data.toString());
    });
    bat.on('exit', (code) => {
          console.log(`Child exited with code ${code}`);
    });
    
  9. 通过fs动态调整模板文件内容

总结

  1. commander的版本不同用法也不一样,新版本需要new一个commander
  2. child_process.exec是开启一个调用命令的进程,可执行cmd,bash,window相关命令
常用命令说明
npm link | unlink -f全局挂载 | 卸载包