Install multitemplate
masterTo use multitemplate in your Go project, download and install it using go get:
go get github.com/gin-contrib/multitemplaterepository·master·Indexed 42 days ago
https://github.com/gin-contrib/multitemplateA custom HTML renderer for the Gin web framework that supports multiple *template.Template instances. It allows developers to define different template sets—such as layouts or partial combinations—and access them by name within a single Gin engine. It supports loading templates from files, globs, fs.FS, and strings, and provides hot reloading when Gin is running in debug mode.
To use multitemplate in your Go project, download and install it using go get:
go get github.com/gin-contrib/multitemplateTo use multitemplate with the Gin web framework, import the package and assign a multitemplate.Renderer to the router.HTMLRender field. This allows you to define multiple template sets (each with its own base files) that can be called by name via c.HTML().
package main
import (
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
)
func createMyRender() multitemplate.Renderer {
r := multitemplate.NewRenderer()
// Register a template named "index" using these files
r.AddFromFiles("index", "templates/base.html", "templates/index.html")
// Register a template named "article" using a different set of files
r.AddFromFiles("article", "templates/base.html", "templates/index.html", "templates/article.html")
return r
}
func main() {
router := gin.Default()
router.HTMLRender = createMyRender()
router.GET("/", func(c *gin.Context) {
c.HTML(200, "index", gin.H{
"title": "Html5 Template Engine",
})
})
router.Run(":8080")
}You can approximate html/template inheritance by dynamically generating template sets. By iterating through an includes/ directory and pairing each include file with a set of layouts/ files, you can create a unique named template for every combination.
Example pattern:
func loadTemplates(templatesDir string) multitemplate.Renderer {
r := multitemplate.NewRenderer()
layouts, _ := filepath.Glob(templatesDir + "/layouts/*.html")
includes, _ := filepath.Glob(templatesDir + "/includes/*.html")
for _, include := range includes {
layoutCopy := make([]string, len(layouts))
copy(layoutCopy, layouts)
files := append(layoutCopy, include)
// Use the filename (e.g., "header.html") as the template name
r.AddFromFiles(filepath.Base(include), files...)
}
return r
}The AddFromFiles method is used to create a named template set by combining multiple files. The first argument is the name of the template, and the subsequent arguments are the paths to the files that compose it.
r.AddFromFiles(name string, files ...string)
r := multitemplate.NewRenderer()
r.AddFromFiles("index", "templates/base.html", "templates/index.html")The Renderer interface provides several methods to add named templates to the registry. Each method returns a *template.Template which can be used for further inspection or configuration.
Add(name string, tmpl *template.Template): Adds an existing *template.Template object.AddFromFiles(name string, files ...string) *template.Template: Loads templates from a list of file paths.AddFromGlob(name, glob string) *template.Template: Loads templates matching a specific glob pattern.AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string) *template.Template: Loads templates from files and applies a template.FuncMap.AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string) *template.Template: Loads templates from files with a FuncMap and additional TemplateOptions.The Render type provides several methods to register templates using different sources. All methods will panic if the template name is empty, the template is nil, or the name already exists in the renderer.
Add(name string, tmpl *template.Template): Adds an existing *template.Template object.AddFromFiles(name string, files ...string): Parses files from the local filesystem.AddFromGlob(name, glob string): Parses files matching a glob pattern.AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string): Parses files with a custom template.FuncMap.AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string): Parses files with a custom FuncMap and custom delimiters.AddFromFS(name string, fsys fs.FS, files ...string): Parses files from an fs.FS (e.g., embed.FS).AddFromFSFuncs(name string, funcMap template.FuncMap, fsys fs.FS, files ...string): Parses files from an fs.FS with a custom FuncMap.AddFromString(name, templateString string): Parses a single template string.AddFromStringsFuncs(name string, funcMap template.FuncMap, templateStrings ...string): Parses multiple template strings with a custom FuncMap.AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string): Parses multiple template strings with a custom FuncMap and custom delimiters.Use New() to create a new Render instance. The Render type is a map of template names to *template.Template objects and implements the gin.HTMLRender interface, allowing it to be used directly with Gin's HTML() method.
import "github.com/gin-contrib/multitemplate"
renderer := multitemplate.New()Use NewDynamic() to create a DynamicRender instance. DynamicRender is a map-based renderer that allows you to dynamically add and manage templates by name. It implements both render.HTMLRender and the project's Renderer interface, making it compatible with Gin's rendering system.
Use NewRenderer() if you want the library to automatically choose between a static Renderer (using New()) or a DynamicRender based on whether Gin is running in debug mode (gin.IsDebugging()).
import "github.com/gin-contrib/gin-contrib/multitemplate"
// Create a dynamic renderer
renderer := multitemplate.NewDynamic()
// Or use the agnostic constructor
renderer := multitemplate.NewRenderer()The Renderer interface is the core component of multitemplate. It implements gin.HTMLRender, allowing it to be used directly with Gin engines. It provides methods to register multiple named templates, which can be loaded from files, globs, file systems (fs.FS), or raw strings.
When running Gin in debug mode, the Renderer supports hot reloading, meaning changes to template files are reflected instantly without restarting the server.
Note: You should always create a Renderer using the multitemplate.NewRenderer() constructor.
// Example of how a Renderer is intended to be used with Gin
// (Requires multitemplate.NewRenderer() implementation)
router := gin.Default()
renderer := multitemplate.NewRenderer()
// Register a template
renderer.AddFromFiles("index", "templates/layout.html", "templates/index.html")
router.SetHTMLRender(renderer)
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index", gin.H{"title": "Hello World"})
})To render a specific template from your Render instance within a Gin handler, use the Instance(name string, data interface{}) method. This returns a render.HTML object which is compatible with Gin's rendering engine.
// Assuming 'renderer' is a multitemplate.Render instance
// and 'user' is your data object
router.GET("/profile", func(c *gin.Context) {
c.Render(http.StatusOK, renderer.Instance("profile", user))
})The DynamicRender type provides several methods to register templates using different sources. Each method associates a name (used to retrieve the template later via .Instance()) with a template built from the specified source.
Add(name string, tmpl *template.Template): Add an existing *template.Template object.AddFromFiles(name string, files ...string): Load templates from local file paths.AddFromGlob(name, glob string): Load templates using a glob pattern.AddFromFS(name string, fsys fs.FS, files ...string): Load templates from an fs.FS (file system).AddFromFSFuncs(name string, funcMap template.FuncMap, fsys fs.FS, files ...string): Load from fs.FS with a custom FuncMap.AddFromString(name, templateString string): Load a single template from a string.AddFromStringsFuncs(name string, funcMap template.FuncMap, templateStrings ...string): Load multiple template strings with a FuncMap.AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string): Load multiple strings with a FuncMap and custom TemplateOptions (like delimiters).AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string): Load from files with a FuncMap.AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string): Load from files with a FuncMap and custom TemplateOptions.// Example: Adding templates from various sources
// 1. From files
renderer.AddFromFiles("user_profile", "templates/layout.html", "templates/profile.html")
// 2. From a glob pattern
renderer.AddFromGlob("admin", "templates/admin/*.html")
// 3. From strings with custom delimiters
options := multitemplate.TemplateOptions{LeftDelimiter: "[[", RightDelimiter: "]]"}
renderer.AddFromStringsFuncsWithOptions("welcome", nil, options, "<h1>Hello {{.Name}}</h1>")
// 4. From an embedded file system
renderer.AddFromFS("static", embedFS, "templates/index.html")You can customize the template delimiters (e.g., changing {{ and }} to something else) using TemplateOptions.
NewTemplateOptions(opts ...TemplateOption): Creates a TemplateOptions struct. Defaults to {{ and }}.WithLeftDelimiter(delim string): Sets the left delimiter.WithRightDelimiter(delim string): Sets the right delimiter.Delims(leftDelim, rightDelim string): Sets both delimiters at once.Pass the TemplateOptions to methods like AddFromFilesFuncsWithOptions or AddFromStringsFuncsWithOptions to apply the custom delimiters to the registered template.
import "github.com/gin-contrib/multitemplate"
// Create options with custom delimiters
opts := multitemplate.NewTemplateOptions(
multitemplate.Delims("<%", %>"),
)
// Use options when adding a template
renderer.AddFromStringsFuncsWithOptions(
"custom_tmpl",
nil, // funcMap
opts,
"<% print .Name %>",
)