首先介绍下在本文出现的几个比较重要的概念:
函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考。
Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考。
2.0 版本的 Fun,在部署这一块做了很多努力,并提供了比较完善的功能,能够做到将云资源方便、平滑地部署到云端。但该版本,在本地开发上的体验,还有较多的工作要做。于是,我们决定推出 Fun Init 弥补这一处短板。
Fun Init: Fun Init 作为 Fun 的一个子命令存在,只要 Fun 的版本大于等于 2.7.0,即可以直接通过fun init
命令使用。Fun Init 工具可以根据指定的模板快速的创建函数计算应用,快速体验和开发函数计算相关业务。官方会提供常用的模板,用户也可以自定自己的模板。
模板项目目录结构
helloworld ① 模板项目根目录
├── metadata.json ② 模板项目配置文件
└── {{ projectName }} ③ 模板根目录
├── index.js
└── template.yml
说明:
- ① 模板项目目录。如果模板项目需要上传到 github,则模板项目名称就是仓库名称
- ② 模板项目配置文件。模板项目配置文件不是必须的,支持两种类型的文件:metadata.json 和 metadata.js
- ③ 模板根目录。
fun init
会从模板根目录开始渲染输出,该目录必须是一个模板表达式。projectName
模板变量来自fun init --name foo
的--name
参数。绝大多数场景,模板根目录叫{{ projectName }}
即可
模板项目配置文件
JSON 风格配置文件
{
"name": "helloworld", ① 模板项目名称
"description": "Print hello world", ② 模板项目描述
"userPrompt": [ ③ 提示输入变量(显式变量)
{
"type": "input", ④ 提示输入类型
"name": "foo", ⑤ 模板变量名
"message": "Please input foo?", ⑥ 提示信息
"default": "{{ projectName }}" ⑦ 模板变量默认值
},
{
"type": "list",
"name": "bar",
"message": "Please select bar?",
"default": "option1",
"choices": ["option1", "option2", "option3"]
}
],
"vars": { ⑧ 隐式变量
"baz": "{{ projectName }}"
},
"copyOnlyPaths": [ "test" ] ⑨ 设置某些目录和文件不需要渲染,只是简单的拷贝
}
说明:
- ① 模板项目名称。对模板项目简单介绍
- ② 模板项目描述。对模板项目详细介绍
- ③ 提示输入变量(显式变量)。在用户初始化模板项目的时候,会显式提示用户输入模板变量,底层用的是 Inquirer,④、⑤、⑥ 和 ⑦ 详情可以参考: Inquirer 文档。当通过
fun init --var foo=xxx
设置了foo
变量后,则不会再提示用户输入foo
变量的值,其他没有设置过的显式变量仍然提示输入 - ⑧ 隐式变量。相对显式变量而言,隐式变量不提示用户输入,可以通过
fun init --var baz=xxx
覆盖配置文件的隐式变量,如果显式和隐式有相同的变量,则该变量不会再提示用户输入,但是这种方式是不推荐使用的,也不要依赖此特性,即显式变量和隐式变量不要有交叉 - ⑨ 设置某些目录和文件不需要渲染,只是简单的拷贝。比如一些二进制文件。格式和
gitignore
是一样的,具体可以参考:gitignore 规范 - 配置文件也可以使用变量,其中,
projectName
模板变量来自fun init --name foo
的--name
参数,还可以使用fun init --var abc=xxx
中的abc
变量,但是,如果你不通过--var
传abc
变量,在渲染配置文件的时候,可能报变量未定义的错误,可以在使用的时候先判断一下,如:{{ typeof x === 'undefined' ? '' : x}}
JS 风格配置文件
module.exports = {
name: 'helloworld', ① 模板项目名称
description: 'Print hello world', ② 模板项目描述
userPrompt: [ ③ 提示输入变量(显式变量)
{
type: 'input', ④ 提示输入类型
name: 'foo', ⑤ 模板变量名称
message: 'Please input foo?', ⑥ 提示信息
'default': '{{ projectName }}' ⑦ 模板变量默认值
},
{
type: 'list',
name: 'bar',
message: 'Please select bar?',
'default': 'option1',
choices: ['option1', 'option2', 'option3'],
when: (answer) => { ⑩ 当前变量是否需要提示
return true
}
}
],
vars: { ⑧ 隐式变量
baz: '{{ projectName }}'
},
copyOnlyPaths: [ 'test' ] ⑨ 设置某些目录和文件不需要渲染,只是简单的拷贝
};
说明:
- ① ~ ⑨ 与前面 JSON 风格配置文件是一样的,但是 JSON 风格配置文件不支持配置函数类型的值,而 JS 风格配置文件是支持。
- ⑩ 当前变量是否需要提示。可以根据用户前面输入的情况决定当前变量是否需要提示,具体可以参考: Inquirer 文档
两种风格的配置文件各有各的优缺点,JSON 风格比较简洁,但是不支持函数;JS 风格略微复杂些,但是支持函数。如果模板项目需要很复杂的提示输入,可以选择 JS 风格。
支持模板语法的位置
- 模板项目配置文件
- 模板根目录
- 模板根目录下的子目录名称(支持多层嵌套)
- 模板根目录下的文件名称(支持多层嵌套)
- 模板根目录下的文件内容(支持多层嵌套)
模板变量设置方式
有三种种方式设置模板变量:
- 参数设置。通过
-V,--var
参数设置模板变量 - 显式变量。配置文件中的
userPrompt
- 隐式变量。配置文件中的
vars
优先级:参数设置 > 隐式变量。
优先级:显式变量 > 隐式变量。
说明:参数设置和显示变量互斥出现,优先级比较没有意义。
模板语法
模板渲染底层是基于 lodash ,详情请参考:lodash 文档。
主要用法:
- 模板表达式
模板表达式的正则表达式规则:/{{([\s\S]+?)}}/g
,以{{
开头,}}
结尾,中间可以是任意字符。
# 假设 foo = 'bar'
hello {{ foo }}! 输出:hello bar!
{{ foo === 'bar' }} 输出:true
{{ _.isEmpty(foo) }} 输出:false
{{ foo ? foo :'unknown' }} 输出:bar
说明:_
是 lodash 对象。
- 模板代码
模板代码的正则表达式规则:/<%([\s\S]+?)%>/g
,以<%
开头,%>
结尾,中间可以是任意字符。
<% if (foo === 'bar') { %> xxxxxxxxx <% } %>
<% _.forEach(users, function(user) { %><li>{{ user }}</li><% }); %>
小结
自定义模板,支持通过配置文件定义渲染规则,模板引擎根据渲染规则渲染模板项目。其中,模板引擎支持模板表达式和模板代码,我们可以通过命令行参数和提示输入方式传递模板变量。