从0手写一个cli 脚手架!!!

### 01 前言

>只是你从事前端开发,无论是什么什么级别的程序员都使用过vue或者是react的脚手架。今天这篇文章就让我们一起从零开始搭建一个自己的脚手架。

**脚手架是干什么的?**

拿vue举例,当我们每一次使用脚手架初始化一个项目的时候,里面就已经有了很多的代码。这就是脚手架为我们初始化的标准项目。也就是说,脚手架会为我们做一些重复性,标准化的事情。

**既然已经有了官方的脚手架,我们为什么还要搭建自己的脚手架?**

1、脚手架会为我们定制一个标准化的项目,那么我们在实际的业务线里面也许就会有自己的定制化需求。如果偶尔一个项目定制化没什么,如果公司的一些项目都采用该标准,那么这个定制化的标准项目,在你们内部就可以理解为标准化了。既然是标准化了,那么他就有必要做一个标准(脚手架)。

2、学习。了解敌人的最好方式,就是加入敌人。我们学习使用一门技术的最好方式,就是将这个技术实现一遍。

话不多说,开干!!!

### 02 功能介绍

知己知彼,方能百战不殆。我们实现一个脚手架,先要知道他能有哪些哪些功能,才能去尝试做这些功能:

1、识别控制台的输入

2、控制台交互

3、将我们的模版项目下载下来

识别控制台的输入

类似于我们在控制台输入  --help,控制台要理解我们的输入内容

控制台交互

我们使用 vue create name 创建项目时候,会让我们选择默认创建,还是配置版创建。如果选择配置版创建,又会让我们选择是否配置vuex,vue-router,eslint这些内容。

![在这里插入图片描述](https://img-blog.csdnimg.cn/2021011002262899.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjM4NTk5,size_16,color_FFFFFF,t_70#pic_center)

将我们的模版项目下载下来

当我们选择完毕之后,会进行下载,下载失败的判断,断网重连的操作等等一系列。

### 03 项目结构

创建一个目录 cuteXuan-cli

然后 npm init -y

目录下创建 bin, lib 文件夹

在bin 下创建文件 xuan,写如下内容

```

#! /usr/bin/env node

console.log("hello cuteXuan-cli")

```

这个时候可以修改我们的 package.json 文件,我们为它添加了bin属性

```

"name": "cuteXuan-cli",

  "version": "1.0.0",

  "description": "",

  "main": "index.js",

  "bin": {

    "cuteXuan-cli": "./bin/xuan",

    "xuan": "./bin/xuan"

  },

```

这个时候我们的最基本结构搭建起来了,是时候执行最重要的一步了:

打开我们的控制台,或者终端。执行下面的命令

```

npm link

// 如果你之前做过类似的操作,也许需要强制这一次的操作

npm link --force

```

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210110022654935.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjM4NTk5,size_16,color_FFFFFF,t_70#pic_center)

如果你的控制台,和我的一样(类似),那么恭喜你,你完成了最最重要的一步。

我们已经将我们自己开发的包(脚手架)放到了全局的npm中。也就是说,这个时候,你已经可以像使用vue,react脚手架一样,全局任何位置操作它的命令了。

注:命令就是我们之前配置在package.json 文件中 bin 属性。cuteXuan-cli和xuan 都可以。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210110022715625.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjM4NTk5,size_16,color_FFFFFF,t_70#pic_center)

如果你走到这,恭喜你,你的脚手架已经完成了一半了。

### 04 利用Commander解析输入参数

```

npm i commander

```

我们平时使用

vue create xxx

vue --version

vue --help

这一类的命令,如果想要执行后续的操作,就要解析用户的输入参数,当然了,-v ,-h 这一类的简写也要考虑。当然了,这些我们都可以借助Commader 来实现。

```

#! /usr/bin/env node

const program = require('commander')

// 重名,需要强制创建的模式

program

    .command('create <app-name')

    .description('create a new project')

    .option('-f, --force','overwrite target directory if it exists')

    .action((name,cmd) => {

      console.log(anme,cmd)

    })

// xuan -v   

program

    .version(`cuteXuan-cli @${require('../package.json').version}`)

    .usage(`<command> [option]`)

// 解析用户执行命令传入的参数

program.parse(process.argv)

```

简单说明一下,

command 里面输入的是我们控制台执行的命令模版  xuan create xxx

description 一些描述文字

option 一些参数配置及简写形式

action 输入正确命令之后的操作

action 中name 是命令,cmd 是参数,但是它不仅仅🈶️我们的参数,还有各种默认的参数。这就需要进行参数清洗:

```

const clearArgs = (cmd) => {

    const args = {}

    cmd.options.forEach(element => {

        const key = element.long.slice(2)

        if (cmd[key]) {

            args[key] =cmd[key]

        }

    });

    return args

}

```

这个时候,我们就可以在我们的action 中拿到正确的name和cmd了。

当然了,一个脚手架会有很多这类型的命令,其他的基本上就是苦力活了。而我们这里仅仅写了最重要的 xuan create name 和 xuan --version

### 05 利用Inquirer 与用户做交互

npm i Inquirer

我们在实际的项目中,会遇到下载不同的版本。就比如我们会使用不同的node版本一样。这个时候就需要进行这样的配置。又比如我们需要为我们的新项目提前一些库,比如vuex,vue-router。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210110022818418.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjM4NTk5,size_16,color_FFFFFF,t_70#pic_center)

当然了,就像前面说的,我们还需要进行版本的选择,这个时候就需要去我们的代码管理地址,获取我们的版本库列表。

github举例子:

https://api.github.com/users/haimingyue/projectName/tags]

```

async getTags() {

  let tags = await fetchTagList()

  if (!tags) { return }

  tags = tags.map(item => item.name)

  let {tag} = await Inquirer.prompt({

      name: "tag",

      type: 'list',

      choices: tags,

      message: "please choose a tag to create project"

  })

  return tag

}   

```

上述代码中type: 'list',就会将我们的tags以列表的形式展示。并返回你选择的tags。

当然了,的配置(vuex,vue-router)列表也是同样的意思,只不过它变成了多选,考虑自己试一试吧!!!

06

使用download-git-repo下载配置模版

到了这一步,我们选择好了项目版本,同时也选择好了项目配置。接下来,就可以将选择变现了——下载到本地。

npm install download-git-repo

值得一提的是,download-git-repo 本身是不支持promise。

```

const downloadGitRepo = require('download-git-repo')

const util = require('util')

const newDownloadGitRepo util.promisify(downloadGitRepo)

```

通过上述方法,可以让 download-git-repo 支持promise形式。

```

/**

*

* @param {*} repo  具体模版

* @param {*} tag  模版的版本号

*/

async download(repo,tag) {

      let requestUrl = `zhu-cli/${repo}${tag?'#'+tag:''}`

      await this.downloadGitRepo(requestUrl,path.resolve(process.cwd),`${repo}@{tag}`)

      return this.target

}

```

到了这个时候,简易版的脚手架就搭建完毕了,发布在npm上,就可以供公司内以及公司外的其他人使用了。当然了,真正的脚手架远比这复杂,我们这仅仅是实现了一个最简单不过的脚手架而已。

### 07 总结

开始功能介绍的时候,也许你自己还有些疑惑,读到了这里。让我们一起回顾一下cli。

初始化项目,并利用 npm link 将我们开发的脚手架与全局的npm联系起

使用 Commander 解析用户的输入,这样就可以对用户的输入作出反应

使用 Inquirer 与用户进行交互。如果没有交互,我们也没有做脚手架的必要了,直接给一个链接它不方便吗?

使用 download-git-repo 将用户的选择的内容 download 到本地

![](https://img-blog.csdnimg.cn/img_convert/e1ca573518207f85eccff5a1eed845c1.bmp)

如果感觉这篇文章对你有帮助,点个赞👍,关注一下吧!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容