I'm new to the world of Golang and I'm trying to set up a web project with templates files and good caching system.
I have layout.html
, 1.html
, 2.html
.
So I load layout.html
in my render function :
err := templates.ExecuteTemplate(w, "layout.html", nil)
layout.html
look like this :
...
<body>{{template "content" .}}</body>
...
1.html
{{define "content"}}This is the first page.{{end}}
2.html
{{define "content"}}This is the second page.{{end}}
I can't use
var templates = template.Must(template.ParseFiles(
"layout.html",
"1.html",
"2.html"))
Because 2.html
override 1.html
.
So I have two ways :
templates["1"] = template.Must(template.ParseFiles("layout.html","1.html")) templates["2"] = template.Must(template.ParseFiles("layout.html","2.html"))
Is there any new way or better way to do this ?
Package-level maps or variables are both a good way to cache compiled templates. Code in #2 above is OK. Here's how to use package-level variables:
var t1 = template.Must(template.ParseFiles("layout.html","1.html"))
var t2 = template.Must(template.ParseFiles("layout.html","2.html"))
Use the variables like this:
err := t1.Execute(w, data)
The code in the question and this code above in this answer load "layout.html" twice. This can be avoided:
var layout = template.Must(template.ParseFiles("layout.html"))
var t1 = template.Must(layout.Clone().ParseFiles("1.html"))
var t2 = template.Must(layout.Clone().ParseFiles("2.html"))
In my projects I use this helper function:
func executeTemplate(tmpls *template.Template, tmplName string, w io.Writer, data interface{}) error {
var err error
layout := tmpls.Lookup("layout.html")
if layout == nil {
return errNoLayout
}
layout, err = layout.Clone()
if err != nil {
return err
}
t := tmpls.Lookup(tmplName)
if t == nil {
return errNoTemplate
}
_, err = layout.AddParseTree("content", t.Tree)
if err != nil {
return err
}
return layout.Execute(w, data)
}
tmpls
is the template which contains all parsed templates as "sub-templates", e.g. from ParseFiles
. layout.html
looks something like this:
<main class="container">
{{template "content" .}}
</main>
While other templates are like this:
<h1>Welcome</h1>
Notice, content templates don't need to start with {{define "content"}}
.