🐱 Mieo,前端“通用”脚手架养成指南
发布于 5 年前 作者 ximolang 5323 次浏览 来自 分享

https___www.lifeofpix.com_wp-content_uploads_2018_06_DSC_2694.jpg

前言

为了让开发者更加便利,初始化项目的 CLI 工具已经成为各个前端框架、或者解决方案的标配。一行命令就可以初始化一个项目,并且还能选择一些配置项来达到自定制的目的,这样的确提高了开发者的效率,提升了使用体验。但是,随着业务中项目的增多,我们会发现这些并不能足够满足需求。

现状

比如,Vue CLI3 提供了诸多配置选项,还能支持视图,Create-React-App 将配置项隐藏,还能给人快速上手、专注业务的体验。但为什么我们会慢慢地觉得这类脚手架无法满足需求?因为这一类 CLI 的作用就是用来初始化一个全新的项目,但除了初始化全新项目之外,还有很多情况是需要复用以前的项目模版的,这些模板可能安装了一些项目中必须要用到的包、或者包含了一些必要的业务模块,这些是上述 CLI 无法满足的。

我们最常用的复用项目模版的方式就是复制,复制无疑是低效的,那既然如此,我们就可以抽出一套代码专门作为具有针对性的项目模板,抽出来之后,通过一行命令就能直接安装搞定,是不是会更轻松。

还有一点,社区有很多开发者写好的模版就放在 Github 上,我们想用的时候会去 Fork 或者 Clone 到本地来做修改。比如备受好评的 vue-element-admin,模板开发者本身是没有提供类似 CLI 来让使用者更便捷的用上这个模板的。那如果有这样一个工具可以一行命令便能初始化,岂不是更好。

进入正题

说了那么多,无非是为了说明 Mieo 这个 CLI 的出发点以及想要达到的效果。同时更多的是想传达一种思想——在遇到特定场景时,可以想办法去改善现有的状况。我并没有调研过是否有其他类似 CLI 可以做这样一个事情,自己的出发点其实就是为了一个场景,我发现每次自己去初始化一个 React 项目的时候,都需要按照 antd 配置一遍 antd、按需加载、覆盖默认配置、Redux 等等一系列的过程,我很累…很明显其他人也会遇到这种情况,所以我建议有需求的都可以自己造个轮子,实现很简单,但会方便不少,而且想尝试一下用 Node 写命令行程序的朋友也能多一点有意义的实践。

废话不多说,我自己初步实现了这样一个 CLI,目前不完善,但是能用。接下来先简单说一下使用方式,然后讲一讲实现思路、技术细节以及之后能做的事情。Mieo 的项目地址为 https://github.com/seymoe/mieo,有兴趣可以去看看,如果有自己实现的想法可以 Fork 或者直接看,代码量不多,但是我基本做了注释,适合新手向,顺便求 🌟 ~

使用方式

  • 安装 Mieo
npm install -g mieo
  • 查看帮助与版本
mieo -h
mieo -V
  • 选择模版,初始化项目,目前模版还只有两个,mieotpl-egg-mongoo-ts和mieotpl-react-antd-ts
mieo init your_project_name

实现思路

思路很简单,我们要做的就是一个命令行程序,能够通过命令执行一系列操作。命令行执行 init 指令,会去查询现有的模板列表,选择模板开始拉取模版到本地,然后自动进行依赖包的安装,最后提示安装成功,可以去按照模板的相应命令进行开发工作了。

技术细节

可执行文件

为了我们的 mieo 命令能够在命令行执行,那我们需要一个可执行文件,Unix 系统上使用 #!/usr/bin/env node 来进行标示,Windows 可能会有兼容性问题,未测试,有兴趣可以在 Power Shell 上尝试。我们在项目中创建了一个 mieo 文件,然后在 package.json 中指定 bin 选项。

"bin": {
    "mieo": "./bin/mieo"
 }

这样我们就能本地测试了,在项目中执行 npm link ,将会创建软连接指向我们这个项目,所以我们可以在其他目录下也能执行 mieo 命令了。

接收命令

项目中采用了 commander 这个库,能方便的生成版本和帮助信息,创建 init 命令的方式也很简单。

    initProgram() {
        this.program = new commander.Command()
        // CLI 的版本信息
        this.program
          .version(pkg.version)
        // init 命令
        this.program
          .command('init <dir>')
          .description('Init a project by choosing template.')
          .action((dir) => initScript(this, dir))
        // 提供系统参数来给 commander 解析
        this.program.parse(process.argv)
    }

config.json

这个文件记录了所以的模板列表,以供使用者选择。

{
  "list": [
    {
      "name": "mieotpl-egg-mongoo-ts",
      "remote": "https://github.com/seymoe/mieotpl-egg-mongoo-ts.git"
    }
  ]
}

init 命令

这个命令接收一个参数,这个参数为文件夹名称。用到了 inquirer 这个库来做用户选择的交互式处理,通过获取 config.json 的数据,供使用者选择,选择之后去看本地的缓存目录是否存在这个模板的源文件,如果有,则比对模板的版本,线上发布的版本比本地的新,则直接进行更新(优化点:给使用者选择的余地),如果版本没有变化则直接拷贝缓存中的文件。然后进入传入的文件夹名称,执行 npm i 的操作(优化点:支持 yarn),安装完成提示。

这里有一点需要注意,因为模版比对方法是 npm view [template name] version --json,所以为了避免比对有误差,需要保证模版的名字在 npm 库中是唯一的,比如我的就是以 mieotpl- 开头。

具体见 源码

关于模板

目前本人是计划完善两个模版,后面有需求再添加:

  1. mieotpl-egg-mongoo-ts eggjs、mongoose的ts模板
  2. mieotpl-react-antd-ts 配好react、antd的ts版本模板(待完成)

总结

在以上的实践里,我们也能发现一些需要优化的点:

  • 在模板版本比对出现差异时,应该把选择权交给用户
  • 安装依赖时,应该给用户选择用 npm 还是 yarn 的余地
  • 执行命令时,没有任何输出,应该优化
  • 加载动画
  • 流程优化,比如选择模版之后显示更多的模版信息
  • 初始化时的文件夹是否已经存在的判断

待优化的点可以解决,但目前对于自己使用已经满足了需求,重点是模版的准备。总体来说,Mieo 只是思路的核心实践,如果真的需要成为一个通用性 CLI,要做的还有很多,相信每个人在实践过程中都会有自己的想法,强烈建议自己尝试一把。

本文首发于 https://www.e7fe.com/post/5d872fc30d44356e1c6c1f70 ,欢迎批评指正。

3 回复

我也想写个类似的… 思路是: 自由组合包, 通过安装 包 来自动生成webpack配置… 然后我写不下去了XD

@lzszone 呃呃呃,我还是想问通过安装 包 来自动生成webpack配置…有啥思路么😂

@ximolang 我的做法是, 通过包最终能得到一个可以被合并的webpack设置对象, 然后用webpack-merge将若干个包和现有的webpack配置合并, 然后webpack的设置就是一个在内存中的js对象了, 然后问题就是内存 => 文件, 思路是…取到值的类型和值, 生成代码节点, 再插入原来webpack config的语法树里面, 再用代码生成器生成代码, 写入 没解决的问题是 除了基础类型…function和函数调用不是特别好搞, 当时想的是应该也能搞, 但是同种级别的不好弄的点稍微有点多, 感觉做出来也不是特别好用, 就没弄啦, 语法树相关的东西其实我用到的很简单, 用到的库有@babel/generator, @babel/parser, 看看文档就能搞

回到顶部