templates

package module
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2021 License: MIT Imports: 10 Imported by: 3

README

Introduction:

This package wraps around the golang html/templates package to provide some additional tooling and aiding in ease of use around working with HTML templates for building web pages.

Details:

  • Works with on-disk or embedded source template files.
  • Store configuration in-package (globally) or elsewhere (dependency injection).
  • Doesn't require a set directory layout.
  • Allows for inheriting some templates, such as headers and footers.
  • Group source templates files into subdirectories for organization.
  • Allows for using the same template name as long as each is in a separate subdirectory.

Getting Started:

With your templates in a directory structure similar to as follows:

/path/to/templates/
├─ header.html
├─ footer.html
├─ docs/
│  ├─ index.html
│  ├─ faq.html
├─ app/
│  ├─ index.html
│  ├─ users.html
  1. Initialize your configuration using NewConfig() or NewOnDiskConfig if you want to store your configuration elsewhere; or DefaultConfig or DefaultOnDiskConfig if you want to use the globally stored configuration.

  2. Call Build() to validate your configuration and parse your template files.

  3. Call Show(w, dir, template, interface{}) to render your parsed template and show it to the user. See more info below.

Using Embedded Files:

This package can work the files embedded via the embded package. You must have already "read" the embedded files using code similar to below prior to providing the embed.FS object to this package. Note that the path must use a forward slash separator!

package main

//go:embed path/to/templates
var embeddedFiles embed.FS

func init() {
    c := NewEmbeddedConfig(embeddedFiles, "path/to/templates", []string{"app", "docs"})
    err := c.Build()
    if err != nil {
        log.Fatal(err)
        return
    }
}

Rendering a Page:

Use code similar to the following, providing your subdirectory the template is located in, the template's name (i.e.: filename), and any data you want to inject into the template for modifying the HTML or displaying.

    func MyHttpHandler(w http.ResponseWriter, r *http.Request) {
    //nil is an interface{} value and can be replaced with anything to
    //be injected into your templates under the .Data field.
    subdir := "app"
    page := "users"
    data := struct{
        Fname  string
        Age    int
        Active bool
    }{"Mike", 46, true}
    templates.Show(w, subdir, page, data)
}

The data parameter can be any data you want, or nil, and is available at the {{.InjectedData}} field.

This package also returns some other information for use when rendering pages:

  • {{.Development}}: boolean field useful for showing a "dev" banner or altering what script are included for diagnostics.
  • {{.UseLocalFiles}}: boolean field used for toggling CSS or JS files between files served from CDN/internet or files served from your local web server/app.
  • {{.CacheBustFiles}}: a set of key-value pairs of the original filename to the filename of the cache busting version of a file for use in replacing the known original filename with the generated cache busting filename. See notes below.

Cache Busting:

This package does not force any style or type of cache busting upon you. You simply need to provide the original file's name and name of the cache busting version of the file as a key-value map.

You must know the original file name of your files (i.e.: script.min.js). If not, this won't work for you. However, if you do, and you have programatic access to the name of the cache busting version of the file, then you can provide the filename pairing and handle the replacement of the original filename in each of your HTML templates using code similar to as follows:

<html>
  <head>
    {{$originalFile := "styles.min.css"}}
	{{$cacheBustFiles := .CacheBustFiles}}

	{{/*If the key "styles.min.css" exists in $cacheBustFiles, then the associated cache-busted filename will be returned as {{.}}. */}}
	{{with index $cacheBustFiles $originalFile}}
	  {{$cacheBustedFile := .}}
	  <link rel="stylesheet" href="/static/css/{{$cacheBustedFile}}">
    {{else}}
      <link rel="stylesheet" href="/static/css/{{$originalFile}}">
    {{end}}
  </head>
</html>

Documentation

Overview

Package templates2 handles parsing and rendering HTML. This more-or-less wraps the golang 'html/template' package with some tooling for storing the parsed templates, showing a requested template, and using source HTML stored in on-disk or embedded files.

Handling of HTML templates is done by parsing files in given directories and caching them for future use within your application. Templates can be stored in numerous subdirectories for ease of organization and allowing the same filename or template declaration ({{define}}) to be used. Files stored at the root templates directory are inherited into each subdirectory; this is useful for storing files with shared {{declare}} blocks that are imported into other templates stored in numerous subdirectories (ex.: header and footers).

Serving of a template is done by providing the subdirectory and name of the template (aka filename). Note that due to this, you cannot serve templates from the root directory. Again, the root directory is for storing templates shared templates between multiple subdirectories.

An example of a directory structure for storing templates is below. templates/ ├─ header.html ├─ footer.html ├─ docs/ │ ├─ index.html │ ├─ faq.html │ ├─ how-to.html ├─ app/ │ ├─ index.html │ ├─ users.html │ ├─ widgits.html

Index

Constants

This section is empty.

Variables

View Source
var (
	//ErrBasePathNotSet is returned if a user calls Save() and not path to the
	//templates was provided.
	ErrBasePathNotSet = errors.New("templates: no value set for TemplatesBasePath")

	//ErrNoSubDirsProvided is returned when no subdirectories were provided. As of
	//now we require at least one subdirectory.
	ErrNoSubDirsProvided = errors.New("templates: no template subdirectories were provided, at least one must be")

	//ErrInvalidSubDir is returned if a user calls Save() and the provided
	//subdirectory cannot be found.
	ErrInvalidSubDir = errors.New("templates: empty or all whitespace string provided for TemplatesSubDirs is not allowed")

	//ErrNoEmbeddedFilesProvided is returned when a user is using a config with embedded files
	//but no embedded files were provided.
	ErrNoEmbeddedFilesProvided = errors.New("templates: no embedded files provided")
)

errors

Functions

func Build

func Build() (err error)

Build builds the templates using the default package level config.

func CacheBustingFilePairs

func CacheBustingFilePairs(pairs map[string]string)

CacheBustingFilePairs sets the CacheBustingFilePairs field on the package level config.

func DefaultConfig

func DefaultConfig()

DefaultConfig initializes the package level config with some defaults set. This wraps NewConfig() and saves the config to the package.

func DefaultEmbeddedConfig

func DefaultEmbeddedConfig(embeddedFS embed.FS, basePath string, subdirs []string)

DefaultEmbeddedConfig initializes the package level config with the path and directories provided and some defaults.

func DefaultFuncMap

func DefaultFuncMap() template.FuncMap

DefaultFuncMap returns the list of extra funcs defined for use in templates.

func DefaultOnDiskConfig

func DefaultOnDiskConfig(basePath string, subdirs []string)

DefaultOnDiskConfig initializes the package level config with the path and directories provided and some defaults.

func Development

func Development(yes bool)

Development sets the Development field on the package level config.

func FuncAddInt

func FuncAddInt(x interface{}, y int) (z int)

FuncAddInt performs addition.

func FuncDateReformat

func FuncDateReformat(date, format string) (d string)

FuncDateReformat is used to transform a date from the yyyy-mm-dd format to another format in templates.

func FuncIndexOf

func FuncIndexOf(needle, haystack string) int

FuncIndexOf returns the position of needle in haystack. If needle does not exist in haystack, -1 is returned.

func PrintEmbeddedFileList

func PrintEmbeddedFileList(e embed.FS)

PrintEmbeddedFileList prints out the list of files embedded into the executable. This should be used for diagnostics purposes only to confirm which files are embedded with the //go:embed directives elsewhere in your app.

func Show

func Show(w http.ResponseWriter, subdir, templateName string, injectedData interface{})

Show handles showing a template using the default package-level config.

func UseLocalFiles

func UseLocalFiles(yes bool)

UseLocalFiles sets the UseLocalFiles field on the package level config.

Types

type Config

type Config struct {
	//Development is passed to each template when rendering the HTML to be sent
	//to the user so that the HTML can be altered based on if you are running
	//your app in a development mode/enviroment. Typically this is used to show
	//a banner on the page, loads extra diagnostic libraries or tools, and uses
	//non-cache busted static files.
	Development bool

	//UseLocalFiles is passed to each template when rendering the HTML to be sent
	//to the user so that the HTML can be altered to use locally hosted third
	//party libraries (JS, CSS) versus libraries retrieve from the internet.
	UseLocalFiles bool

	//BasePath is the full path to the directory where template files are stored
	//not including any subdirectories. There should be at least one template file
	//at this path. Files in this directory will be inherited into each subdirectory
	//when the templates are parsed; this is useful for commonelements such as
	//headers, footers, and scripts. For handling embedded files, this would be set
	//to a path based upon the location of your package main file. See
	//https://pkg.go.dev/embed#hdr-Directives for more information.
	BasePath string

	//SubDirs is a list of subdirectories of the BasePath where you store template
	//files. This may be empty if you have no subdirectories. This must only be the
	//actual directory names, not full paths. Full paths will be constructed from
	//BasePath.
	SubDirs []string

	//Extension is the extension you use for your HTML files. This defaults to "html".
	Extension string

	//UseEmbedded means files built into the golang executable will be used rather
	//than files stored on-disk. You must have read the embedded files, with code
	//such as var embeddedFiles embed.FS, prior and you must provide the embed.FS to
	//the field EmbeddedFS.
	UseEmbedded bool

	//EmbeddedFiles is the filesystem embedded into this executable via the embed package.
	//You must have read the embedded files, with code such as var embeddedFiles embed.FS,
	//prior and you must set UseEmbedded to true to enable use of these files.
	EmbeddedFS embed.FS

	//FuncMap is a collection of functions that you want to use in your templates to
	//augment the golang provided templating funcs. This package provides some default
	//extra funcs in templates-templatefuncs.go. See https://pkg.go.dev/text/template for
	//more info.
	//To provide extra funcs to templates, use code such as the following:
	/*
		config, err := templates..DefaultOnDiskConfig("/path/to/templates", []string{"subdir1", "subdir2"})
		if err != nil {
			//handle err
		}
		config.FuncMap = template.FuncMap{
			"indexOf":   templates.FuncIndexOf,
			"myNewFunc": myNewFunc,
		}
		err = config.Build()
		if err != nil {
			//handle err
		}
	*/
	FuncMap template.FuncMap

	//CacheBustingFilePairs is a key-value list of filesnames that match up an original
	//file name to the file's cache busting file name. This list is then passed to your
	//templates when rendered to replace the known original filename (i.e.: script.min.js)
	//with the cache busting filename that is most likely programmatically created (i.e.:
	//A1B2C3D4.script.min.js). See the package github.com/c9845/cachebusting for an example
	//implementation and tooling.
	//
	//To use the cache busting file, you would use template code similar to the following
	//to handle the filename replacement:
	/*
		<head>
			{{$originalFile := "styles.min.css"}}
			{{$cacheBustFiles := .CacheBustFiles}}

			{{/*If the key "styles.min.css" exists in $cacheBustFiles, then the associated cache-busted filename will be returned as {{.}}. *\/}}
			{{with index $cacheBustFiles $originalFile}}
			{{$cacheBustedFile := .}}
			<link rel="stylesheet" href="/static/css/{{$cacheBustedFile}}">
			{{else}}
			<link rel="stylesheet" href="/static/css/{{$originalFile}}">
			{{end}}
		</head>
	*/
	CacheBustingFilePairs map[string]string
	// contains filtered or unexported fields
}

Config is the set of configuration settings for working with templates.

func GetConfig

func GetConfig() (c *Config)

GetConfig returns the current state of the package level config.

func NewConfig

func NewConfig() *Config

NewConfig returns a config for managing your templates with some defaults set.

func NewEmbeddedConfig

func NewEmbeddedConfig(embeddedFS embed.FS, basePath string, subdirs []string) *Config

NewEmbeddedConfig returns a config for managing your templates when the source files are stored embedded in the app executable.

func NewOnDiskConfig

func NewOnDiskConfig(basePath string, subdirs []string) *Config

NewOnDiskConfig returns a config for managing your templates when the source files are stored on disk.

func (*Config) Build

func (c *Config) Build() (err error)

Build handles finding the templates files, parsing them, and building the golang templates. This func works by looking for files with the correct extension in the provided BasePath and in subdirectories built from the BasePath and each SubDirs provided. Templates in subdirectories inherit templates from the base directory (for usage of common templates such as headers, footers). Files in each subdirectory are handled independently and cannot reference a template from another subdirectory; this allows for templates that use the same name ({{define}}) or same filename to exist and be used.

func (*Config) Show

func (c *Config) Show(w http.ResponseWriter, subdir, templateName string, injectedData interface{})

Show renders a template as HTML. This returns the page to the user's browser. This works by taking a subdirectory's name subdir and the name of a template (a filename) templateName and looks up the associated template that was parsed earlier returning it with any injected data and cache busting files. Note that the user provided injectedData will be available at {{.Data}} in HTML templates.

Jump to

Keyboard shortcuts

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