/page

A simple Go module that makes it easier to render Go HTML templates.

Primary LanguageGoMIT LicenseMIT

Version Built with GoLang License Go Report Card Tests

page

This is a simple package that makes rendering Go html templates as painless as possible. It has no dependencies outside of the standard library.

Installation

Install it the usual way:

go get -u github.com/tsawler/page

Usage

To use, import github.com/tsawler/page, and create a variable of type page.Render, either by using the New() method, or by manually constructing the variable.

At the minimum, you must specify the directory where your templates live with the TemplateDir field, and a list of partials you want to include, with the Partials field.

If you set UseCache to true, then every time a template is rendered it will be stored in the TemplateMap field, which is of type map[string]*template.Template. This way, pre-parsed templates can be read very quickly from memory, rather than rebuilding them from disk on every request, which is an expensive operation.

Example

Assuming that you have two Go templates named base.layout.gohtml and home.page.gohtml which look like this...

{{define "base"}}
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    {{block "content" .}}

    {{end}}
    </body>
    </html>
{{end}}
{{template "base" .}}

{{define "content"}}
    <h1>Hello, world!</h1>
    <p>{{index .Data "payload"}}</p>
{{end}}

... then you can use code like this:

package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"

	"github.com/tsawler/page"
)

const port = ":8080"

type Data struct {
	Data map[string]any
}

func main() {

	render := page.Render{
		TemplateDir: "./templates",
		TemplateMap: make(map[string]*template.Template),
		Functions:   template.FuncMap{},
		Debug:       true,
		UseCache:    true,
	}

	// Call LoadLayoutsAndPartials to automatically load all such files in TemplateDir.
	err := render.LoadLayoutsAndPartials([]string{".layout"})
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		data := make(map[string]any)
		data["payload"] = "This is passed data."
		err := render.Show(w, "home.page.gohtml", &Data{Data: data})
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			log.Println(err)
			return
		}
	})

	http.HandleFunc("/string", func(w http.ResponseWriter, r *http.Request) {
		data := make(map[string]any)
		data["payload"] = "This is passed data."
		out, err := render.String("home.page.gohtml", &Data{Data: data})
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			log.Println(err)
			return
		}
		log.Println(out)
		fmt.Fprint(w, "Check the console; you should see html")
	})

	log.Println("Starting on port", port)
	err = http.ListenAndServe(port, nil)
	if err != nil {
		log.Fatal(err)
	}
}