1

I am doing some web develoment using the go programming language using the package html/template. At some point of the code, I need to call the function template.ParseFiles(...) so I can create a template from those files ad then execute it using temp.Execute(w,data). I would like to know if it is better to create the template on each request or to do it once in the main and declare a global variable.

Right now I do it on each request on my handle functions, like most tutorials do. However, I don't know If I'm wasting resources by doing it on each request instead of having them as global variables.

This is how it looks on each request

func ViewStats(w http.ResponseWriter, r *http.Request) {
    //Get stuff from db and put them in data
    //...
    //return data to user
    tmp, err := template.ParseFiles("views/guest-layout.html",
        "views/stats.html")

    if err != nil {
        fmt.Println(err)
    } else {
        tmp.Execute(w,data)
    }
}

I would like to know if this is better:

var temp1 template.Template

func main() {
    temp1, err = template.ParseFiles("file1","file2") 
    //...
}
  • 3
    Once. Attach the parsed template value to a struct type.that handles your routes - that way it's closely coupled with your API handler. – colm.anseo Apr 02 '19 at 02:54
  • @colminator so I use it as a global variable? – Eduardo Andrés Castillo Perera Apr 02 '19 at 02:58
  • 2
    Parsing the template once reduces execution time of the handler that uses the template. A package-level variable is a fine way to hold on to the parsed template. – Charlie Tumahai Apr 02 '19 at 03:05
  • 1
    @Eduardo it's a matter of style. I generally don't like globals, but in the context of a single purpose package, there's nothing wrong with that choice. – colm.anseo Apr 02 '19 at 03:19
  • Note that there are no globals in Go, so you can't actually store your templates in a global variable. – Jonathan Hall Apr 02 '19 at 06:25
  • 1
    See possible duplicate [It takes too much time when using “template” package to generate a dynamic web page to client in Golang](https://stackoverflow.com/questions/28451675/it-takes-too-much-time-when-using-template-package-to-generate-a-dynamic-web-p/28453523#28453523). – icza Apr 02 '19 at 06:35

1 Answers1

2

As usual: It depends.

But first some nuance:

  1. You should never do template parsing (or anything else interesting) in your main() function. Instead, your main() function should call methods (or a single method) that kicks off the chain of interesting things in your program.

  2. Go doesn't have globals, so it's not actually an option to store your parsed templates in a global variable in the first place. The closest Go has to global variables is package variables. You could store your parsed templates in a package variable in the main package, but this is also bad form, as your main package (except for tiny, trivial programs), should just be an entry point, and otherwise nearly empty.

But now, on to the core of your question:

Should you parse templates per request, or per run?

And here it depends.

If you have templates that change frequently (i.e. during development, when you're constantly editing your HTML files), once per request can be best.

But this is far less efficient than just parsing once, so in production, you may wish to parse the templates once on startup only. Then you can store the templates in a package variable, or better, in a struct that is initialized at runtime. But I leave that to you.

But what may be best is actually a bit of a compromise between the two approaches. It may be best to load your templates at start-up, and re-load them occasionally, either automatically (say, every 5 minutes), or watch your filesystem, and reload them whenever the on-disk representation of the templates changes.

How to do this is left as an exercise for the reader.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Another solid option (my personal preference, but it is slightly more complicated) is to use build constraints to parse templates at startup unless e.g. a `dev` build tag is passed, in which case they're loaded on each request. That lets you do rapid iteration while working locally, and get maximum performance in production without having to watch files or reload on a timer. – Adrian Apr 02 '19 at 13:48