forked https://github.com/foolin/goview
Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.
go get github.com/aveyuan/goview- Lightweight - use golang html/template syntax.
- Easy - easy use for your web application.
- Fast - Support configure cache template.
- Include syntax - Support include file.
- Master layout - Support configure master layout file.
- Extension - Support configure template file extension.
- Easy - Support configure templates directory.
- Auto reload - Support dynamic reload template(disable cache mode).
- Multiple Engine - Support multiple templates for frontend and backend.
- No external dependencies - plain ol' Go html/template.
- Gin - Provide Gin adapter via
supports/ginview.
See https://pkg.go.dev/github.com/aveyuan/goview
- ginview goview adapter for Gin framework (see
supports/ginview)
Project structure:
|-- app/views/
|--- index.html
|--- page.html
|-- layouts/
|--- footer.html
|--- master.html
Use default instance:
//write http.ResponseWriter
//"index" -> index.html
goview.Render(writer, http.StatusOK, "index", goview.M{})Use new instance with config:
gv := goview.New(&goview.Config{
Root: "views",
Extension: ".tpl",
Master: "layouts/master",
Partials: []string{"partials/ad"},
Funcs: template.FuncMap{
"sub": func(a, b int) int {
return a - b
},
"copy": func() string {
return time.Now().Format("2006")
},
},
DisableCache: true,
Delims: Delims{Left: "{{", Right: "}}"},
})
//Set new instance
goview.Use(gv)
//write http.ResponseWriter
goview.Render(writer, http.StatusOK, "index", goview.M{})Use multiple instance with config:
//============== Frontend ============== //
gvFrontend := goview.New(&goview.Config{
Root: "views/frontend",
Extension: ".tpl",
Master: "layouts/master",
Partials: []string{"partials/ad"},
Funcs: template.FuncMap{
"sub": func(a int, b int) int {
return a + b
},
"copy": func() string {
return time.Now().Format("2006")
},
},
DisableCache: true,
Delims: Delims{Left: "{{", Right: "}}"},
})
//write http.ResponseWriter
gvFrontend.Render(writer, http.StatusOK, "index", goview.M{})
//============== Backend ============== //
gvBackend := goview.New(&goview.Config{
Root: "views/backend",
Extension: ".tpl",
Master: "layouts/master",
Partials: []string{"partials/ad"},
Funcs: template.FuncMap{
"sub": func(a int, b int) int {
return a - b
},
"copy": func() string {
return time.Now().Format("2006")
},
},
DisableCache: true,
Delims: Delims{Left: "{{", Right: "}}"},
})
//write http.ResponseWriter
gvBackend.Render(writer, http.StatusOK, "index", goview.M{})goview.Config{
Root: "views", //template root path
Extension: ".tpl", //file extension
Master: "layouts/master", //master layout file
Partials: []string{"partials/head"}, //partial files
Funcs: template.FuncMap{
"sub": func(a, b int) int {
return a - b
},
// more funcs
},
DisableCache: false, //if disable cache, auto reload template file for debug.
Delims: Delims{Left: "{{", Right: "}}"},
}DisableCache can be changed safely at runtime via the ViewEngine methods.
- Do NOT mutate
Config.DisableCachedirectly while the engine is in use. - Use
SetDisableCacheinstead.
gv := goview.New(&goview.Config{DisableCache: false})
// enable auto reload (disable template cache)
gv.SetDisableCache(true)
// disable auto reload (enable template cache)
gv.SetDisableCache(false)
_ = gv.DisableCache()//template file
{{include "layouts/footer"}}Render name use index without .html extension, that will render with master layout.
- "index" - Render with master layout.
- "index.html" - Not render with master layout.
Notice: `.html` is default template extension, you can change with config
Render with master
//use name without extension `.html`
goview.Render(w, http.StatusOK, "index", goview.M{})The w is instance of http.ResponseWriter
Render only file(not use master layout)
//use full name with extension `.html`
goview.Render(w, http.StatusOK, "page.html", goview.M{})We have two type of functions global functions, and temporary functions.
Global functions are set within the config.
goview.Config{
Funcs: template.FuncMap{
"reverse": e.Reverse,
},
}//template file
{{ reverse "route-name" }}Temporary functions are set inside the handler.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := goview.Render(w, http.StatusOK, "index", goview.M{
"reverse": e.Reverse,
})
if err != nil {
fmt.Fprintf(w, "Render index error: %v!", err)
}
})//template file
{{ call $.reverse "route-name" }}goview provides a set of built-in template functions globally.
- These functions are available in all templates without extra configuration.
Config.Funcscan override any built-in function with the same name.
default(d, v) any
Returns d when v is considered empty.
Empty means:
nilfalse- numeric
0 - empty string
- empty slice/map/array
- zero-value struct
Example:
{{ default "N/A" .Name }}list(v1, v2, ...) []any
Example:
{{ index (list 1 2 3) 1 }}dict(k1, v1, k2, v2, ...) (map[string]any, error)
Keys must be strings and the argument count must be even.
Example:
{{ $m := dict "a" 1 "b" 2 }}
{{ index $m "a" }}urlquery(v) template.URL
URL-escapes the value for use in query strings.
Example:
<a href="/search?q={{ urlquery .Keyword }}">search</a>date(t, layout) (string, error)
Supported input types: time.Time, *time.Time, int64, int.
Example:
{{ date .CreatedAt "2006-01-02 15:04:05" }}json(v) (template.JS, error)
Marshals to JSON using encoding/json.
Example:
<script>window.__DATA__ = {{ json . }}</script>escape(v) template.HTML
HTML-escapes the value (uses template.HTMLEscapeString).
Example:
{{ escape .UnsafeText }}safeHTML(v) template.HTML
Marks the value as trusted HTML.
Use this only when you know the content is safe. Do NOT use it directly on user input.
Example:
{{ safeHTML .TrustedHTML }}include(name) (template.HTML, error)
Renders another template and returns the result.
Example:
{{ include "layouts/footer" }}goview is based on Go html/template, so the standard template syntax and the built-in functions are available.
- Action:
{{ ... }} - Pipeline:
{{ .Title | printf "%q" }} - If/Else:
{{ if .OK }}yes{{ else }}no{{ end }}- Range:
{{ range .Items }}{{ . }}{{ end }}- With:
{{ with .User }}{{ .Name }}{{ end }}- Template / define:
{{ define "content" }}...{{ end }}
{{ template "content" . }}- Logic/compare:
and,or,not,eq,ne,lt,le,gt,ge - Length:
len - Index:
index - Print:
print,printf,println - Call function:
call
See the official docs for the full list and details:
See _examples/ in this repository.
package main
import (
"fmt"
"net/http"
"github.com/aveyuan/goview"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := goview.Render(w, http.StatusOK, "index", goview.M{"title": "Index title!"})
if err != nil {
fmt.Fprintf(w, "Render index error: %v!", err)
}
})
fmt.Println("Listening and serving HTTP on :9090")
_ = http.ListenAndServe(":9090", nil)
}package main
import (
"net/http"
"github.com/aveyuan/goview/supports/ginview"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.HTMLRender = ginview.Default()
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index", gin.H{"title": "Index title!"})
})
_ = router.Run(":9090")
}See _examples/ in this repository.