echoo,一个灵活的,可配置的模板生成 CLI 工具。
不同于集成在脚手架中的 CLI,echoo 是一个独立的 CLI 工具,通过简单的配置,你就可以拥有一套自己的模板 CLI 。
- 内置模板
echoo 内置了两款基于 luban 的 React 模板。你可以直接在一个基于 luban 的项目中使用 echoo。
- 灵活配置
不同的项目对于模板有着不同的要求,echoo 最核心的功能实际上是提供一个工具,让开发者可以通过自己编写配置文件,开发出符合自己的模板。
# setup echoo
ech init
echoo 将会在 process.cwd()
目录中生成以下文件
+ cwd/echoorc.js
+ cwd/echoo
+ cwd/echoo/component.art
通过 init
命令,你可以快速搭建 echoo 的配置环境
目前不在 npm 中,需要在本地通过 npm link 使用。 请在 macOS 环境下使用。
- clone 仓库
git clone https://github.com/meakle/echoo.git
- 打开仓库
- 运行 npm 脚本
npm start
- 开始使用 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 分为两部分
- 配置文件
- 模板代码
开发者通过编写配置文件,抽象出生成代码的逻辑,最后再根据模板代码生成最终的代码
-
导出一个名为
generator
的函数 -
函数中参数有一个名为
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,如下图
在编写 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 中是如何处理路径的:
-
/
开头 -> 直接判断为绝对路径 -
./
开头 -> 相对于配置文件的路径 -
字符开头 -> 相对于
cwd
的路径
echoo 采用 art-template 作为模板渲染引擎,对于模板也沿用了 art-template 的模板语法。比如使用上面的例子:
在渲染的时候,data 中的属性将作为值,结合模板传递给 art-template 渲染出最终的代码。
- 需要创建的文件已经存在,如何处理?
- 需要新增代码的文件不存在,如何处理?
在出现异常的时候 echoo 将会中断文件的生成,并且抛出问题
对于文件已经存在的文件
- 覆盖
- 跳过该 action
- 取消本次命令
新增代码的文件不存在
- 跳过本次 action
- 取消命令
- 为什么不在脚手架中内置模板
因为不够灵活,随着项目的发展,一个脚手架级别的模板代码大概率不适合项目,而 echoo 本身是独立的,可以在项目中编写配置文件,根据不同的需求变换配置。
- 为什么不用代码片段(自动补全)
不在一个层面,echoo 能直接生成文件夹/文件,并且可以在已有的文件中追加内容。而代码片段终究只能一个文件一个文件的操作。并且有很多内部封装的工具并没有现成代码片段。
- 为什么不用 Yeoman
它太重了,我只想要模板生成功能
- 为什么不用 plop
真诚的说,echoo 的创意和思路来自于 plop。echoo 在一段时间里只是对 plop 的一层 CLI 包装,但是我发现仅仅是封装 plop 其体验并不算好。因此我阅读了 plop 的源码,独立完成了 echoo。
plop 是非常好的,其更加灵活,功能也更加强大。echoo 对比 plop 多了两点功能,一是内置了代码,二是处理了一些异常情况。
echoo 是一个试验品,起源于我想学习 node.js,顺带着就了解到了更多新东西。