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}}