Go: Templates
Is it just me? I can never remember how to use html/template
in Go and I can never make sense of the docs either, which I feel are
accurate but present the material in essentially random order. Here’s
the cheat sheet.
A Template is a
tree of templates
The most important thing to understand about Go templates is that a
Template is not necessarily a single template, but
potentially a whole tree of templates that can have other associated
templates. All the API weirdness of text/template, namely
that you can’t just load a template into a variable but must also give
it another name with New(), flows from this fact. Without
knowing this, the New() function’s naming requirement makes
no sense.
This ought to be the first thing you learn, but it’s buried in a
minor section of the text/template docs halfway down the
page, after you’ve covered such things as multi-way equality tests in
the template language’s boolean operators. See associated
templates.
Loading a template
The awkwardness of
New()
template.New("file.html").ParseFiles("file.html")
If you’re loading a single template from a file, this gets awkward.
You may want to give your template a memorable name, a reasonable thing
to want. But the argument to New() has to be the same as
the actual filename, or else you get errors (“error: template: […] is an
incomplete or empty template”).
You can just use
ParseFiles
template.ParseFiles("file.html") // victory
The docs almost go out of their way to hide that these functions
exist in the package, because ParseFiles() and friends are
listed under “Types” > “type Template” with the methods
of Template, instead of under “Functions”, where all the
other non-method functions are listed.
Anyways, use them and you get the same result as if you had used
New(filename).ParseFiles(filename).
Load templates from an embedded FS
//go:embed dir
var _dir embed.FS
template.ParseFS(fs, "file.html")
You can load templates from an embed.FS using
ParseFS instead of ParseFiles.
(Yes, there has to be no space in //go:embed or else it
doesn’t work.)
Executing a template
You can execute a template from code, or from within another template.
From code
t.Execute(writer, data)
writer is an io.Writer and thus can be an
http.ResponseWriter.
From another template
{{template "name" pipeline}}