搭建个人脚手架

1,314 阅读5分钟

前言

相关技术栈和依赖

  • javascript
  • 发布 npm 包。
  • commander 包的使用
  • download-git-repo 包的使用

分析

脚手架 vue-cli 相信大家都使用过,很便捷。

# 全局安装 vue cli 包
npm install -g @vue/cli-service-global

# 使用vue cli 内置指令创建一个工程
vue create hello-world

# 运行项目
cd hello-world
npm i
npm run dev

几个指令就搭建好一个前端工程。

这边文章目的是教会大家如何发布个人的脚手架。

主要步骤如下:

  • 部署自己的 npm 包
  • 全局安装自己所部署的包后,要支持使用我们自定义的指令
  • 配置好一个前端工程,并推送到git代码库
  • 根据指令触发,拉取代码仓库到本地

发布 npm 包,支持使用指令

没有发布 npm 包经验的同学看这里:发布 npm 包

发布的包如何像以下这样,支持使用指令?

vue create hello-world

第一步:指令配置

在包的 package.json 文件增加以下指令配置

// package.json
{
  ...
  "bin": {
    "wfj-cli": "./index.js"
  },
  ...
}

bin 属性用于配置指令,指令由 keyvalue 组成,key 为指令名,vaule 为运行指令后要执行的文件。

第二步:修改要执行的文件

index.js

#!/usr/bin/env node

console.log('hello world')

可以看到在 index.js 的首行为 #!/usr/bin/env node

该行作用为:使用系统下的 env 文件找到 node 安装位置,并使用 node 执行该文件。

第三步:重新部署并全局安装使用

重新部署 npm 包后,需全局安装我们部署的包,因为要使用指令必须得全局安装。

npm i -g packName

使用指令

# 执行以下指令,相当于执行了 node index.js
wfj-cli

# 执行结果
hello world

到这里,我们已经成功发布一个支持使用简单指令的 npm 包了,它只能根据指令去执行对应的文件。

如何处理更复杂的指令?

  • 像 vue cli 这样,接收到指令上的参数'hello-world' 作为创建文件夹的名称
vue create hello-world

让我们接着往下走。

commander 包的使用

commander 是一个 npm 包,是完整的 node.js 命令行解决方案。

使用 commander 可以完美解决接收指令参数、设置多个子指令等问题。

想快速上手使用,可以看我整理的使用概览:commander包使用说明

想更深入的学习请前往:官方使用说明

这边只介绍搭建脚手架需要用到的部分

继续修改上文的 index.js 文件

#!/usr/bin/env node

  const { program } = require('commander')

  // 设置指令版本
  program.version('0.0.1')

  program
    // 增加指令
    .command('init')
    // 设置指令参数
    .arguments('<filderName>')
    // 指令的描述
    .description('初始化 wfj-cli 脚手架')
    // 执行指令的回调
    .action((filderName) => {
      console.log(filderName)
    })

  // 该行放置末尾,解析option方法所构建的参数
  program.parse(process.argv)

我们使用 command 方法添加了 init 指令,以及接受 filderName 参数,并在执行指令回调函数中打印 filderName 参数。

本地运行测试

node index.js init hello-world

# 执行结果
hello-world

这样一来,我们就可以获取到指令上的参数 hello-world 了

重新部署 npm 包,并更新本地包后运行

# 更新本地包
npm update -g packName 

# 执行
wfj-cli init hello-world

# 执行结果
hello-world

到这里,我们的包可以接收到指令上的参数了。

拉取代码仓库到本地

使用 download-git-repo 包可以将代码仓库 clone 到本地。

var download = require('download-git-repo');

/**
 * 第一个参数:[github/gitlab]:[账户名]/[仓库名]
 * 第二个参数:下载后存放路径
 * 第三个参数:响应回调
 */
download('github:wenfujie/wenfujie.github.io', 'test/tmp', function (err) {
  console.log(err ? err : 'Success')
})

用法相对简单,需注意的是:

  • 第一个参数格式是 [github/gitlab]:[账户名]/[仓库名]
  • 第二个参数是下载存放路径,我们只需将该值设置为上文取到的指令参数,即可达到自定义工程名称的目的。

继续修改 index.js

#!/usr/bin/env node
// 上一行作用:使用env来找到node,并使用node来作为程序的解释程序

// 异步方式转化为promise形式
const { promisify } = require('util')
// 显示进程进度
const ora = require('ora')
const { program } = require('commander')
const downloadGitRepo = require('download-git-repo')
// clone 的仓库
const REPO_DESC = 'github:wenfujie/search-360-bd'

// 主入口
function main() {
  const cb = (filderName) => {
    clone(REPO_DESC, filderName)
  }
  registerCommand(cb)
}

main()

/**
 * 注册指令
 * @param {function} callback 执行指令的回调函数
 */
function registerCommand(callback) {
  program.version('0.0.1')

  program
    .command('init')
    .arguments('<filderName>')
    .description('脚手架初始化的描述')
    .action((filderName) => {
      typeof callback && callback(filderName)
    })

  program.parse(process.argv)
}

/**
 * 下载git仓库代码
 * @param {string} repo git仓库地址
 * @param {string} repo 下载要存放目录
 */
async function clone(repo, desc) {
  const down = promisify(downloadGitRepo)
  const downProgress = ora(`下载${repo}中...`)
  await down(repo, desc)
    .then((res) => {
      downProgress.succeed('下载成功')
    })
    .catch((err) => {
      downProgress.failed()
    })
}

这里用到一个 node 工具 promisify,作用是将异步回调的方法编译为支持 Promise 形式使用。

重新部署并更新本地包

# 更新本地包
npm update -g packName 

# 执行
wfj-cli init hello-world

# 执行成功后,会在本地生成 hello-world 文件夹,并将 git 仓库克隆到文件夹下

到这里,我们就搭建了一个简版脚手架。

结尾

  • 我们可以配置不同的子指令,或者参数控制,来下载不同的 git 仓库,或者控制是否初始化 vuex 、router等模块。
  • 脚手架的核心观念其实是复用,这跟模块化开发思想类似。
  • 搭建脚手架,能在要创建新工程时,快速的搭建好开发环境,而不是拷贝工程再去删除不需要文件和修改冗余代码。开发过程中会有很多重复性工作,比如自动化部署,尽量使用工具来释放我们双手提高开发效率。

本文涉及到相关知识点

文中涉及到的完整代码

发布npm包

快速上手commander包

我的其他文章

使用node实现自动化部署

我的前端知识库