Skip to content
/ echoo Public

一个灵活的,可配置的模板生成 CLI 工具

Notifications You must be signed in to change notification settings

meakle/echoo

Repository files navigation

echoo

JavaScript Style Guide ts

echoo,一个灵活的,可配置的模板生成 CLI 工具。

不同于集成在脚手架中的 CLI,echoo 是一个独立的 CLI 工具,通过简单的配置,你就可以拥有一套自己的模板 CLI 。

  1. 内置模板

echoo 内置了两款基于 luban 的 React 模板。你可以直接在一个基于 luban 的项目中使用 echoo。

HNe0xS.gif

HNn2cT.gif

  1. 灵活配置

不同的项目对于模板有着不同的要求,echoo 最核心的功能实际上是提供一个工具,让开发者可以通过自己编写配置文件,开发出符合自己的模板。

# setup echoo
ech init

echoo 将会在 process.cwd() 目录中生成以下文件

+ cwd/echoorc.js
+ cwd/echoo
+ cwd/echoo/component.art

通过 init 命令,你可以快速搭建 echoo 的配置环境

HtRk3n.gif

使用

目前不在 npm 中,需要在本地通过 npm link 使用。 请在 macOS 环境下使用。

  1. clone 仓库
git clone https://github.com/meakle/echoo.git
  1. 打开仓库
  2. 运行 npm 脚本
npm start
  1. 开始使用 echoo
Usage: ech [options] [command]

Options:
  -e, --external-templates         Using external templates
  -p, --configuration-path <path>  Specifies the absolute path to the configuration file
  -V, --version                    output the version number
  -h, --help                       display help for command

Commands:
  gen                              Generating a template file
  init                             quick setup echoo
  help [command]                   display help for command

自定义模板

echoo 分为两部分

  • 配置文件
  • 模板代码

开发者通过编写配置文件,抽象出生成代码的逻辑,最后再根据模板代码生成最终的代码

配置文件的编写

  1. 导出一个名为 generator 的函数

  2. 函数中参数有一个名为 gen ,通过该该参数,注册生成器

export function generator (gen) {
	gen({
    // .....
  })
  // 你也可以注册多个生成器
  gen({})
}

gen 函数中传入一个对象作为参数,该对象必须满足如下类型:

{
	name: string
	description: string
	prompts: Array
	actions: Array | () => Array
}
  • name:生成器的名字
  • description:生成器的描述
  • prompts:交互式的提问,将收集的答案结合模板代码渲染
  • actions:具体的动作,后文会详细说明

其中关于 prompts 如何编写你可以查阅 inquirer 文档。

此时,我们可以编写这样的配置文件

export function generator (gen) {
  gen({
    name: 'first',
    description: 'first generator',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name'
      }
    ],
    actions: data => {
      // ...
      return []
    }
  })
    gen({
    name: 'second',
    description: 'second generator',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name'
      }
    ],
    actions: data => {
      // ...
      return []
    }
  })
}

此时,运行 echoo,如下图

HtbStP.gif

Actions 字段的编写

在编写 actions 之前,我们思考一个问题,通过一个模板文件生成文件的本质是什么?

实际上就是读取指定位置的模板文件,然后再将模板文件写入指定位置。因此,我们需要以下几个信息:

  • 模板文件路径:templatePath
  • 指定写入的路径:path

我们的模板文件并不是死的,因此我们还需要有一个 data 作为信息提供给模板文件,再结合模板渲染引擎,渲染出我们需要的模板。因此我们还需要:

  • 数据:data

到这里已经具备了大部分必要的条件,但是 echoo 除了提供生成新的模板,还提供在原有的文件上面添加新代码的功能,因此我们还需要:

  • 指定其生成类型:type
  • 对本次操作的描述:description

一次操作所必要的属性如下:

action = {
	type: 'add' | 'append'
	description: string
	path: string
	templatePath: string
	data: Object
}

现在我们已经将一次对文件的操作抽象成了代码,是不是很简单?

actions 字段接受数组或者一个返回数组的函数。如果选择函数,那么 echoo 将把 prompts 中获取到的数据作为参数传入函数中,提供给用户使用。

export function generator (gen) {
  gen({
    name: 'first',
    description: 'first generator',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name'
      }
    ],
    actions: data => {
      // data 是一个对象,其值是 prompts 收集的回答
      const { name } = data
      const resultList = []
			// 定义一个 action
      const component = {
        type: 'add',
        description: `[add] ${name} component`,
        path: `${name}/index.tsx`,
        templatePath: './echoo/component.art',
        data: {
          componentName: name
        }
      }

      resultList.push(component)

      return resultList
    }
  })
}

最后,我们再关注一下 echoo 中是如何处理路径的:

  1. / 开头 -> 直接判断为绝对路径

  2. ./ 开头 -> 相对于配置文件的路径

  3. 字符开头 -> 相对于 cwd 的路径

模板代码

echoo 采用 art-template 作为模板渲染引擎,对于模板也沿用了 art-template 的模板语法。比如使用上面的例子:

在渲染的时候,data 中的属性将作为值,结合模板传递给 art-template 渲染出最终的代码。

import React, { FC } from "react";

const {{componentName}}: FC = () => {

  return (
    <div>
      <h1>Hello echoo</h1>
    </div>
  );
};

export { {{componentName}} };

异常处理

  • 需要创建的文件已经存在,如何处理?
  • 需要新增代码的文件不存在,如何处理?

在出现异常的时候 echoo 将会中断文件的生成,并且抛出问题

对于文件已经存在的文件

  1. 覆盖
  2. 跳过该 action
  3. 取消本次命令

新增代码的文件不存在

  1. 跳过本次 action
  2. 取消命令

为什么不

  1. 为什么不在脚手架中内置模板

因为不够灵活,随着项目的发展,一个脚手架级别的模板代码大概率不适合项目,而 echoo 本身是独立的,可以在项目中编写配置文件,根据不同的需求变换配置。

  1. 为什么不用代码片段(自动补全)

不在一个层面,echoo 能直接生成文件夹/文件,并且可以在已有的文件中追加内容。而代码片段终究只能一个文件一个文件的操作。并且有很多内部封装的工具并没有现成代码片段。

  1. 为什么不用 Yeoman

它太重了,我只想要模板生成功能

  1. 为什么不用 plop

真诚的说,echoo 的创意和思路来自于 plop。echoo 在一段时间里只是对 plop 的一层 CLI 包装,但是我发现仅仅是封装 plop 其体验并不算好。因此我阅读了 plop 的源码,独立完成了 echoo。

plop 是非常好的,其更加灵活,功能也更加强大。echoo 对比 plop 多了两点功能,一是内置了代码,二是处理了一些异常情况。

碎碎念

echoo 是一个试验品,起源于我想学习 node.js,顺带着就了解到了更多新东西。

About

一个灵活的,可配置的模板生成 CLI 工具

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published