Nodejs创建自己的cli脚手架

467 阅读2分钟

一:什么是脚手架?

脚手架就是「为了减少重复性工作而做的工具」

二:怎么搭建脚手架?

2.1 搭建脚手架所需要的构建工具

  1. commander.js 用于读取和解析命令行参数取值
  2. Inquirer.js 交互式的读取命令行参数
  3. download-git-repo 可以用于下载git仓库代码
  4. ora 加载动画

2.2 最简单搭建过程

  1. 创建文件,npm初始化

mkdir chenjinqiu-cli

npm init

  1. 创建bin文件夹,下面创建index.js,作为主的文口,并在package.json添加入口

"bin": { "chenjinqiu-cli": "./bin/index.js" }

  1. 在执行命令的index.js文件下添加如下代码

#!/usr/bin/env node

console.log(1)

  1. 命令行操作

npm link

chenjinqiu-cli

以上就是最简单的搭建过程,但是我们的需求远远不止于此,我们可能会选择不同的模板,我们需要拉取github的代码,我们需要优雅的交互等等,下面就看看我们从零到一的整个过程

2.3 脚手架从零到一

  1. 使用command创建读取命令文件夹名称,通过inquirer,选择不同模板,config配置不同的下载地址,并配置不同创建目录下载,ora加载动画
const config = {
    "chenjinqiu-component":{
      url: "chenjnqiu/createComponent",
    },
    "chenjinqiu-reduxHooks":{
      url: "chenjnqiu/chenjinqiu-reduxHooks",
    }
}
const program = require('commander')
const inquirer = require('inquirer')
const download = require('download-git-repo')
const loading = ora('Loading');
program.command('create <app-name>')
  .action((appName) => {
      inquirer.prompt([{
      type: 'input',
      name: 'description',
      message: '请输入项目描述信息:',
    }, {
      type: "list",
      message: "请选择一个模板下载:",
      name: "templateName",
      choices: Object.keys(config)
    }]).then(async (answers) => {
      const { description, templateName } = answers
      // 当前目录创建根据appName输入项目目录文件
      const appDir = path.join(process.cwd(), appName);
      try {
          loading.start();
          download(config[templateName], appDir, (err) => {
              if(err) {
                   loading.fail();
              } else {
                  loading.succeed();
              }
          })
      } catch (error) {
        console.log(error);
      }
    })

  })

download-git-repo 的地址使用方式有多种,具体可以看官方文档www.npmjs.com/package/dow… , 试过{clone: true}的方式指定分支,总是会有问题,所以最后转而用最简单直接的文件目录方式,并把默认的main分支改为master

  1. 每次下载之前先检测文件是否存在,存在的话删除文件
const delDir = (path, isRoot) => {
    return new Promise((resolve) => {
        let files = [];
        if (fs.existsSync(path)) {
            files = fs.readdirSync(path);
            files.forEach((file, index) => {
                let curPath = path + "/" + file;
                if (fs.statSync(curPath).isDirectory()) {
                    delDir(curPath); //递归删除文件夹
                } else {
                    fs.unlinkSync(curPath); //删除文件
                }
            });
            fs.rmdirSync(path);
        }
        if (isRoot && !fs.existsSync(path)) {
            resolve({ status: true })
        }
    })
}
  1. 更改package.json的name和描述内容
updatePackage = (appDir, creditData) => {
    return new Promise((resolve, reject) => {
        const filename = path.join(appDir,'package.json');
        fs.readFile(filename, 'utf8', (err, data) => {
            if (!err) {
                const packageJson = JSON.parse(data);
                const newPackageJson = JSON.stringify({ ...packageJson, ...creditData}, null, '\t')  // \t为了输出更好看
                fs.writeFileSync(filename, newPackageJson)
            }
        })
    })
};
  1. 自动安装,我们依然可以通过inquirer的交互方式,选择是npm安装或者yarn安装
const installType = {
  yarn: "yarn install",
  npm: "npm install"
}

 inquirer.prompt({
        type: "list",
        message: "请选择安装方式:",
        name: "installType",
        choices: Object.keys(installType)
    }).then(async (answers) => {
        const { installType } = answers
        const workerProcess = exec(
            installType,
            {
              cwd: appDir,
            },
            (err) => {
              if (err) {
                console.log(err);
                reject(err);
              } else {
                resolve(null);
              }
            }
          );
          workerProcess.stdout.on('data', function (data) {
            console.log(data);
          });
      
          workerProcess.stderr.on('data', function (data) {
            console.log(data);
          });
    })

添加自动启动,也是类似的方式处理

三:发npm 包

  1. 如果是非npm 镜像,切换成npm镜像

npm config set registry https://registry.npmjs.org

  1. 登录账号

npm login

  1. 发版

npm publish

以上就是整个cli创建过程,具体代码参考github.com/chenjnqiu/c…

参考文章地址: juejin.cn/post/717428… zhuanlan.zhihu.com/p/414966591