使用 Go 渲染模板
模板引擎是软件开发者的常用工具。绝大部分 Web 软件开发者会使用某种引擎渲染 HTML 页面;一些数据工程师也有使用模板引擎的经历,比如知名的数据转换工具 DBT 使用了 Python 编写的 Jinja 模板,用于渲染数据转换的 SQL 代码。简单的模板引擎可能只是变量替换,复杂一些的模板引擎还提供了分支、循环等控制结构,以及模块化的代码组织机制。而在 Web 时代出生的 Go 语言,在标准库内置了就内置了支持文本和HTML渲染的模板库。
Go 语言中的模板引擎 🔗
标准库中的模板引擎 🔗
Go标准库里包括用于渲染文本的 text/template 和渲染HTML的 html/template,支持添加模板中的函数。不过它使用了一种不太常见的语法,初学者可能不太习惯。但是,依然有一些很知名的开源项目在使用它。比如用于生成静态网站的 Hugo,以及 Kubernetes 的包管理工具 Helm。其中,Helm 除了添加自定义的 include
required
等函数外,并还使用了第三方 sprig 扩展了模板函数,见其文档 《Know Your Template Functions》。
第三方开源模板引擎 🔗
除标准库之外,开源的模板引擎(或者模板语言)还有:
- 类Django语法的 pongo2
- Mustache 的实现 hoisie/mustache
- Handlebars 的实现 aymerick/raymond
- 用于编写 HTML 模板且具备类型检查的 a-h/templ
更多的使用 Go 编写的模板引擎可见 Awesome Go 的 Template Engines。
text/template
的使用示例 🔗
text/template 的文档详细介绍了模板的使用方法,在不再赘述。这里给出一个真实的例子:假定在一个复杂的项目中,需要渲染多个模板文件,而这些文件又共用了一些片段,如何组织代码呢?这个场景非常类似于 Helm 中的模板:templates/
里的每个文件是部署到 Kubernetes 中的一种 Kind
,共用的片段位于 _helper.tpl
文件中。
代码 🔗
为了便于演示,创建一个极简的示例:
- 创建
templates
文件夹。包括两个文件:main.yaml
和helper.tpl
。 - Go 代码:
main.go
。
templates/main.yaml
内容如下:
title: {{ template "main.title" }}
templates/helper.tpl
内容如下:
{{ define "main.title" -}}
This is the title
{{- end }}
main.go
内容如下:
package main
import (
"log"
"os"
"text/template"
)
func main() {
if err := invoke(); err != nil {
log.Fatalln(err)
}
}
func invoke() error {
tmpl, err := template.New("main.yaml").ParseFiles("./templates/main.yaml", "./templates/helpers.tpl")
// or
// tmpl, err := template.ParseFiles("./templates/main.yaml", "./templates/helpers.tpl")
if err != nil {
return err
}
if err := tmpl.Execute(os.Stdout, nil); err != nil {
return err
}
return nil
}
执行 go run main.go
之后,控制台的输出内容为:
title: This is the title
代码解释 🔗
- Go 代码中的
template.ParseFiles
函数创建了一个新的模板,其参数为文件路径,它会解析这些文件里的模板函数。最终渲染的文件是该函数的第一个参数。 helpers.tpl
里的define
是一个 Action,用于定义一个模板(另一个定义模板的 Action是block
,它是define
的快捷方式);在其他模板中,可使用template
和模板名称执行这个模板。