如何搭建一个自己的脚手架

脚手架

搭建脚手架的目的就是快速的搭建项目的基本结构并提供项目规范和约定。目前日常工作中常用的脚手架有 vue-cli、create-react-app、angular-cli 等等,都是通过简单的初始化命令,完成内容的快速构建。

其实我们也可以用git clone url来新建(复制)项目,再 low 一点的方法就是复制粘贴整个文件夹,一样也能达到初始化的目的。

脚手架的本质也是从远程下载一个模板来进行一个新项目,但是脚手架可是高级版的克隆,它主要是提供了交互式的命令让我们可以动态的更改模板,然后用一句命令就可以实现其他内置依赖的初始化,方便了多人协作,不需要将文件传来传去。

接下来我们就开始实现一个简易版的脚手架heaven-cli(可自行命名),目标是实现一个heaven init template-name project-name这样的命令,废话少说,开始进入正题吧!

前置知识了解

其实一个简易版的 heaven-cli的代码量并不多,所以这里我们先来介绍一下其中要使用到的第三方库

commander

这是用来编写指令和处理命令行的,用法如下:

const program = require("commander");
// 定义指令
program
  .version('0.0.1')
  .command('init', 'Generate a new project from a template')
  .action(() => {
    // 回调函数
  })
// 解析命令行参数
program.parse(process.argv);
复制代码

inquirer

这是个强大的交互式命令行工具,用法如下:

const inquirer = require('inquirer');
inquirer
  .prompt([
    // 一些交互式的问题
  ])
  .then(answers => {
    // 回调函数,answers 就是用户输入的内容,是个对象
  });
复制代码

chalk

这是用来修改控制台输出内容样式的,起到了美化输出内容的作用,用法如下:

const chalk = require('chalk');
console.log(chalk.green('success'));
console.log(chalk.red('error'));
复制代码

ora

这是一个好看的加载交互组件,用于下载过程中的loading效果,用法如下:

const ora = require('ora')
let spinner = ora('downloading template ...')
spinner.start()
复制代码

download-git-repo

用于下载远程模板的,支持 GitHub、 GitLab 和 Bitbucket 等,用法如下:

const download = require('download-git-repo')
download(repository, destination, options, callback)
复制代码

其中 repository 是远程仓库地址;destination 是存放下载的文件路径,也可以直接写文件名,默认就是当前目录;options 是一些选项,比如{ clone:boolean }表示用 http download 还是 git clone 的形式下载。

初始化目录

首先我们先创建一个空文件夹,取名 heaven-cli;

目录结构

├── bin //可执行文件
└── lib
    ├── init.js         //init command
    ├── template 
        └── index.js        //内置的所有模版
    └── utils
        └── utils.js        // 公共方法
├── package.json
├── README.md
复制代码

在该目录下执行npm init命令,进行初始化。

安装依赖

npm install  chalk commander inquirer ora download-git-repo
复制代码

我这边的package.json的依赖是这样的

"dependencies": {
    "chalk": "^4.1.2",
    "commander": "^8.3.0",
    "download-git-repo": "^3.0.2",
    "inquirer": "^8.1.2",
    "ora": "^5.4.1"
}
复制代码

node.js 内置了对命令行操作的支持,package.json 中的 bin 字段可以定义命令名和关联的执行文件。在 package.json 中添加 bin 字段

"bin": {
    "heaven": "bin/heaven.js"
  },
复制代码

bin 目录下新建一个heaven.js,并在行首加入一行 #!/usr/bin/env node 指定当前脚本由node.js进行解析

#!/usr/bin/env node
const program = require('commander')

const init = require("../lib/init");

program
  .command('init <template> <app-name>')
  .description('generate a project from a remote template (legacy API, requires @heaven-cli)')
  .action((template, name) => {
    init(template, name)
  })
  
// 解析命令行参数
program.parse(process.argv)
复制代码

这个文件的主要作用就是定义指令,我们用node ./bin/heaven运行一下,就能看到运行结果了,

当然,在开发过程中为了方便调试,在当前的 heaven-cli 目录下执行 npm link,将 heaven 命令链接到全局环境,

这样我们每次只要输入heaven,就可以直接运行了。

后面就可以编写 /lib/init.js的代码了

// 交互式命令行
const inquirer = require('inquirer')
// 修改控制台字符串的样式
const chalk = require('chalk')
// node 内置文件模块
const fs = require('fs')
// 读取template下内置的模版
const tplObj = require("./template")

// 下载
const download = require("download-git-repo");

// 自定义交互式命令行的问题及简单的校验
let question = [
  {
    name: "name",
    type: 'input',
    message: "Project name (" + name + ')',
    validate (val) {
      if (val === '') {
        return 'Name is required!'
      } else {
        return true
      }
    }
  },
  {
      name: "description",
      type: 'input',
      message: "Project description"
  },
]

inquirer
  .prompt(question).then(answers => {
    // answers 就是用户输入的内容,是个对象
    let {
        description
      } = answers;
      let projectName = answers.name
      // 出现加载图标
      const spinner = ora("Downloading...");
      
      const url = tplObj.template[template]
      // 执行下载方法并传入参数
      download(
        url,
        projectName,
        err => {
          if (err) {
            spinner.fail();
            console.log(chalk.red(`Generation failed. ${err}`))
            return
          }
          // 将用户输入的内容,写入package.json内
          const packageFile = path.join(process.cwd(), projectName + '/package.json');
          const package = require(packageFile);
          package.description = description;
          package.name = projectName;
          fs.writeFileSync(file, `module.exports = ${JSON.stringify(package, null, '\t')};`, 'utf8');
          // 结束加载图标
          spinner.succeed();
          console.log(chalk.green('\n Generation completed!'))
          console.log('\n To get started')
          console.log(`\n    cd ${projectName} \n`)
        }
      )
  })
复制代码

至此,一个小小的脚手架就做完了。

接下来就测试一下heaven init vue my-project命令能否生效

image.png

很快就可以看到已经成功初始化了my-project,此时可以看一下my-project文件夹下面


image2.png

发布到 npm

既然以上命令可以执行成功了,那接下来我们就把它发布到 npm 上吧,其它用户就可以通过 npm install heaven-cli-fe -g 全局安装。 即可使用 heaven 命令。

源码地址:github.com/hujinbin/he…

可使用 template 包含如下

  • vue
  • vue-seo
  • koa-react
  • koa-vue
  • microservice

vue

  • vue-cli,webpack5.28版本

vue-seo (开发中)

  • 基于vue-cli搭建的伪ssr脚手架,webpack5.28版本,打包生成对应的静态html,并跳转到真实网址,用于seo搜索。

koa-react

  • koa+react 工程项目骨架,ssr模式,支持mysql和mongodb数据库

koa-vue

  • koa+vue 工程项目骨架 mvc结构, 前端vue单页面应用

microservice (开发中)

  • 基于vite搭建微前端脚手架

原文链接:如何搭建一个自己的脚手架- 惊觉

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

推荐阅读更多精彩内容