got

package module
v0.0.0-...-7a56faf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2020 License: MIT Imports: 18 Imported by: 0

README

Go T(emplates)

The native Go html/template library is powerful. Template inheritance, helper functions, and proper sanitizing of HTML, CSS, and Javascript are all provided. However, using html/template requires a bit of boilerplate (and forethought) which this package provides in a clever, minimal wrapper.

  1. This library is for people who want use html/template.
  2. This package requires you to organize your templates on-disk in a certain, logical way.

Usage

Specify the directory containing your templates, and the file extension for template files.

templates, err := got.New("templates/", ".html")

Once loaded, rendering templates inside a handler is as easy as passing the http.ResponseWriter, template name, data, and a status.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  data = struct{ Name string }{"Bob"}
  err := templates.Render(w, "home", data, http.StatusOK)

  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
})

Should an error be encountered, got will prevent a partial response from being sent, allowing you to handle the error (as shown above).

Conventions

xeoncross/got expects layout files to live in one of three folders based on their usage:

  • pages are the "main content" for your routes
  • includes are shared code blocks such as "sidebars" or "ads"
  • layouts are the different page "shells" used by pages.

Each page is the "starting" point. For example, you might have a file structure like this:

pages/
  home.html
  about.html
  profile.html
  posts.html
layouts/
  main.html
  forum.html
includes/
  sidebar.html

In this example, imagine the "profile" and "posts" page use the forum.html layout, while the "home" & "about" pages use main.html + sidebar.html. Every page has access to all includes.

The Pain Point: Inheritance

With plain html/template you can't specify a template parent from the child. Instead, you have to load templates backwards by loading the child, then having the parent template.Execute() to render the child correctly inside it.

t, _ := template.ParseFiles("base.tmpl", "about.tmpl")
t.Execute(w, nil)

Solution

We solve this problem by adding a simple template comment to the child:

{/* use mobilelayout */}

This comment is removed by html/template in the final output, but tells got to load this child template inside mobilelayout.html.

Subfolders

Simple sites can easily fit everything under the pages, includes, and layouts namespaces. However, for better organization of your HTML snippets you can also use subfolders. For example, you might have custom sidebar modules you wish to isolate to their own files. Including items in subfolders (and beyond) is as easy as regular files. Imagine you had the following file:

/templates/includes/sidebar/active_users.html

You can access this in your templates using the string includes/sidebar/active_users.

Benchmarks

This library adds almost no overhead to html/template for rendering templates. This package is all about layout conventions without interfering with performance.

$ go test -bench=. --benchmem -test.cpu=1

BenchmarkCompile         	  300000	      4079 ns/op	    1256 B/op	      30 allocs/op
BenchmarkNativeTemplates 	  300000	      4028 ns/op	    1256 B/op	      30 allocs/op

This library is as fast as html/template because the organizational sorting and inheritance calculations are performed on the initial load.

Template functions provide handy helpers for doing common tasks. The Masterminds/sprig package contains +100 helper functions (inspired by underscore.js) you can use to augment your templates.

If building HTML forms, or using the CSS framework Bootstrap, you might want to look at gobuffalo/tags for helper functions to generate HTML.

Alternatives

There are a number of template engines available should you find html/template lacking for your use case. @SlinSo has put together a good benchmark of these different template engines.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultFunctions = template.FuncMap{
	"title":     strings.Title,
	"upper":     strings.ToUpper,
	"lower":     strings.ToLower,
	"trim":      strings.TrimSpace,
	"urlencode": url.QueryEscape,

	"yesno": func(yes string, no string, value bool) string {
		if value {
			return yes
		}
		return no
	},

	"plural": func(one, many string, count int) string {
		if count == 1 {
			return one
		}
		return many
	},

	"date": func() string {
		return time.Now().Format("2006-01-02")
	},

	"unixtimestamp": func() string {
		return fmt.Sprintf("%d", time.Now().Unix())
	},

	"json": func(v interface{}) string {
		output, _ := json.Marshal(v)
		return string(output)
	},

	"noescape": func(a ...interface{}) template.HTML {
		return template.HTML(fmt.Sprint(a...))
	},

	"noescapeurl": func(u string) template.URL {
		return template.URL(u)
	},

	"sha256": func(input string) string {
		hash := sha256.Sum256([]byte(input))
		return hex.EncodeToString(hash[:])
	},

	"sha1": func(input string) string {
		hash := sha1.Sum([]byte(input))
		return hex.EncodeToString(hash[:])
	},

	"md5": func(input string) string {
		hash := md5.Sum([]byte(input))
		return hex.EncodeToString(hash[:])
	},

	"base64encode": func(v string) string {
		return base64.StdEncoding.EncodeToString([]byte(v))
	},
	"base64decode": func(v string) string {
		data, err := base64.StdEncoding.DecodeString(v)
		if err != nil {
			return err.Error()
		}
		return string(data)
	},
	"base32encode": func(v string) string {
		return base32.StdEncoding.EncodeToString([]byte(v))
	},
	"base32decode": func(v string) string {
		data, err := base32.StdEncoding.DecodeString(v)
		if err != nil {
			return err.Error()
		}
		return string(data)
	},
}

DefaultFunctions for templates

Functions

This section is empty.

Types

type NotFoundError

type NotFoundError struct {
	Name string
}

NotFoundError for type assertions in the caller while still providing context

func (*NotFoundError) Error

func (t *NotFoundError) Error() string

type Templates

type Templates struct {
	Extension string
	Dir       string
	Templates map[string]*template.Template
}

Templates Collection

func New

func New(templatesDir, extension string, functions template.FuncMap) (*Templates, error)

New templates collection

func (*Templates) Compile

func (t *Templates) Compile(template string, data interface{}) (*bytes.Buffer, error)

Compile the template and return the buffer containing the rendered bytes

func (*Templates) DefinedTemplates

func (t *Templates) DefinedTemplates() (out string)

DefinedTemplates loaded by got (for debugging)

func (*Templates) Funcs

func (t *Templates) Funcs(functions template.FuncMap) *Templates

Funcs function map for templates

func (*Templates) Render

func (t *Templates) Render(w http.ResponseWriter, template string, data interface{}, status int) error

Render the template & data to the ResponseWriter safely

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL