goview

by foolin

foolin / goview

Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for...

179 Stars 18 Forks Last release: 8 months ago (v0.3.0) MIT License 59 Commits 6 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

goview

GoDoc Widget Travis Widget GoReportCard Widget

Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.

Contents

Install

go get github.com/foolin/goview

Features

  • 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.
  • Gorice - Support gorice for package resources.
  • Gin/Iris/Echo/Chi - Support gin framework, Iris framework, echo framework, go-chi framework.

Docs

See https://www.godoc.org/github.com/foolin/goview

Supports

Usage

Overview

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,
    })

//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, b int) int {
                return a - b
            },
            "copy": func() string {
                return time.Now().Format("2006")
            },
        },
        DisableCache: true,
    })

//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, b int) int {
            return a - b
        },
        "copy": func() string {
            return time.Now().Format("2006")
        },
    },
    DisableCache: true,
})

//write http.ResponseWriter
gvBackend.Render(writer, http.StatusOK, "index", goview.M{})

Config

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.
}

Include syntax

//template file
{{include "layouts/footer"}}

Render name:

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)

go
//use full name with extension `.html`
goview.Render(w, http.StatusOK, "page.html", goview.M{})

Custom template functions

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" }}

Examples

See _examples/ for a variety of examples.

Basic example

package main

import ( "fmt" "github.com/foolin/goview" "net/http" )

func main() {

//render index use `index` without `.html` extension, that will render with master layout.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "index", goview.M{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
    if err != nil {
        fmt.Fprintf(w, "Render index error: %v!", err)
    }

})

//render page use `page.tpl` with '.html' will only file template without master layout.
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
    if err != nil {
        fmt.Fprintf(w, "Render page.html error: %v!", err)
    }
})

fmt.Println("Listening and serving HTTP on :9090")
http.ListenAndServe(":9090", nil)

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html

See in "examples/basic" folder ```

Basic example

Gin example

go get github.com/foolin/goview/supports/ginview
package main

import ( "github.com/foolin/goview/supports/ginview" "github.com/gin-gonic/gin" "net/http" )

func main() { router := gin.Default()

//new template engine
router.HTMLRender = ginview.Default()

router.GET("/", func(ctx *gin.Context) {
    //render with master
    ctx.HTML(http.StatusOK, "index", gin.H{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
})

router.GET("/page", func(ctx *gin.Context) {
    //render only file, must full name with extension
    ctx.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
})

router.Run(":9090")

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html

See in "examples/basic" folder ```

Gin example

Iris example

$ go get github.com/foolin/goview/supports/irisview
package main

import ( "github.com/foolin/goview/supports/irisview" "github.com/kataras/iris/v12" )

func main() { app := iris.New()

// Register the goview template engine.
app.RegisterView(irisview.Default())

app.Get("/", func(ctx iris.Context) {
    // Render with master.
    ctx.View("index", iris.Map{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
})

app.Get("/page", func(ctx iris.Context) {
    // Render only file, must full name with extension.
    ctx.View("page.html", iris.Map{"title": "Page file title!!"})
})

app.Listen(":9090")

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html

See in "examples/iris" folder ```

Iris example

Iris multiple example

package main

import ( "html/template" "time"

"github.com/foolin/goview"
"github.com/foolin/goview/supports/irisview"
"github.com/kataras/iris/v12"

)

func main() { app := iris.New()

// Register a new template engine.
app.RegisterView(irisview.New(goview.Config{
    Root:      "views/frontend",
    Extension: ".html",
    Master:    "layouts/master",
    Partials:  []string{"partials/ad"},
    Funcs: template.FuncMap{
        "copy": func() string {
            return time.Now().Format("2006")
        },
    },
    DisableCache: true,
}))

app.Get("/", func(ctx iris.Context) {
    ctx.View("index", iris.Map{
        "title": "Frontend title!",
    })
})

//=========== Backend ===========//

// Assign a new template middleware.
mw := irisview.NewMiddleware(goview.Config{
    Root:      "views/backend",
    Extension: ".html",
    Master:    "layouts/master",
    Partials:  []string{},
    Funcs: template.FuncMap{
        "copy": func() string {
            return time.Now().Format("2006")
        },
    },
    DisableCache: true,
})

backendGroup := app.Party("/admin", mw)

backendGroup.Get("/", func(ctx iris.Context) {
    // Use the ctx.View as you used to. Zero changes to your codebase,
    // even if you use multiple templates.
    ctx.View("index", iris.Map{
        "title": "Backend title!",
    })
})

app.Listen(":9090")

}

Project structure: ```go |-- app/views/ |-- fontend/ |--- index.html |-- layouts/ |--- footer.html |--- head.html |--- master.html |-- partials/ |--- ad.html |-- backend/ |--- index.html |-- layouts/ |--- footer.html |--- head.html |--- master.html

See in "examples/iris-multiple" folder ```

Iris multiple example

Echo example

Echo <=v3 version:

bash
go get github.com/foolin/goview/supports/echoview

Echo v4 version:

go get github.com/foolin/goview/supports/echoview-v4
package main

import ( "github.com/foolin/goview/supports/echoview" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "net/http" )

func main() {

// Echo instance
e := echo.New()

// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())

//Set Renderer
e.Renderer = echoview.Default()

// Routes
e.GET("/", func(c echo.Context) error {
    //render with master
    return c.Render(http.StatusOK, "index", echo.Map{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
})

e.GET("/page", func(c echo.Context) error {
    //render only file, must full name with extension
    return c.Render(http.StatusOK, "page.html", echo.Map{"title": "Page file title!!"})
})

// Start server
e.Logger.Fatal(e.Start(":9090"))

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html

See in "examples/basic" folder ```

Echo example Echo v4 example

Go-chi example

package main

import ( "fmt" "github.com/foolin/goview" "github.com/go-chi/chi" "net/http" )

func main() {

r := chi.NewRouter()

//render index use `index` without `.html` extension, that will render with master layout.
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "index", goview.M{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
    if err != nil {
        fmt.Fprintf(w, "Render index error: %v!", err)
    }
})

//render page use `page.tpl` with '.html' will only file template without master layout.
r.Get("/page", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
    if err != nil {
        fmt.Fprintf(w, "Render page.html error: %v!", err)
    }
})

fmt.Println("Listening and serving HTTP on :9090")
http.ListenAndServe(":9090", r)

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html

See in "examples/basic" folder ```

Chi example

Advance example

package main

import ( "fmt" "github.com/foolin/goview" "html/template" "net/http" "time" )

func main() {

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,
})

//Set new instance
goview.Use(gv)

//render index use `index` without `.html` extension, that will render with master layout.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "index", goview.M{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
    if err != nil {
        fmt.Fprintf(w, "Render index error: %v!", err)
    }

})

//render page use `page.tpl` with '.html' will only file template without master layout.
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "page.tpl", goview.M{"title": "Page file title!!"})
    if err != nil {
        fmt.Fprintf(w, "Render page.html error: %v!", err)
    }
})

fmt.Println("Listening and serving HTTP on :9090")
http.ListenAndServe(":9090", nil)

}

Project structure: ```go |-- app/views/ |--- index.tpl
|--- page.tpl |-- layouts/ |--- footer.tpl |--- head.tpl |--- master.tpl |-- partials/ |--- ad.tpl

See in "examples/advance" folder ```

Advance example

Multiple example

package main

import ( "html/template" "net/http" "time"

"github.com/foolin/goview"
"github.com/gin-gonic/gin"

)

func main() { router := gin.Default()

//new template engine
router.HTMLRender = gintemplate.New(gintemplate.TemplateConfig{
    Root:      "views/fontend",
    Extension: ".html",
    Master:    "layouts/master",
    Partials:  []string{"partials/ad"},
    Funcs: template.FuncMap{
        "copy": func() string {
            return time.Now().Format("2006")
        },
    },
    DisableCache: true,
})

router.GET("/", func(ctx *gin.Context) {
    // `HTML()` is a helper func to deal with multiple TemplateEngine's.
    // It detects the suitable TemplateEngine for each path automatically.
    gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
        "title": "Fontend title!",
    })
})

//=========== Backend ===========//

//new middleware
mw := gintemplate.NewMiddleware(gintemplate.TemplateConfig{
    Root:      "views/backend",
    Extension: ".html",
    Master:    "layouts/master",
    Partials:  []string{},
    Funcs: template.FuncMap{
        "copy": func() string {
            return time.Now().Format("2006")
        },
    },
    DisableCache: true,
})

// You should use helper func `Middleware()` to set the supplied
// TemplateEngine and make `HTML()` work validly.
backendGroup := router.Group("/admin", mw)

backendGroup.GET("/", func(ctx *gin.Context) {
    // With the middleware, `HTML()` can detect the valid TemplateEngine.
    gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
        "title": "Backend title!",
    })
})

router.Run(":9090")

}

Project structure: ```go |-- app/views/ |-- fontend/ |--- index.html |-- layouts/ |--- footer.html |--- head.html |--- master.html |-- partials/ |--- ad.html |-- backend/ |--- index.html |-- layouts/ |--- footer.html |--- head.html |--- master.html

See in "examples/multiple" folder ```

Multiple example

go.rice example

go get github.com/foolin/goview/supports/gorice
package main

import ( "fmt" "github.com/GeertJohan/go.rice" "github.com/foolin/goview" "github.com/foolin/goview/supports/gorice" "net/http" )

func main() {

//static
staticBox := rice.MustFindBox("static")
staticFileServer := http.StripPrefix("/static/", http.FileServer(staticBox.HTTPBox()))
http.Handle("/static/", staticFileServer)

//new view engine
gv := gorice.New(rice.MustFindBox("views"))
//set engine for default instance
goview.Use(gv)

//render index use `index` without `.html` extension, that will render with master layout.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "index", goview.M{
        "title": "Index title!",
        "add": func(a int, b int) int {
            return a + b
        },
    })
    if err != nil {
        fmt.Fprintf(w, "Render index error: %v!", err)
    }

})

//render page use `page.tpl` with '.html' will only file template without master layout.
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
    err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
    if err != nil {
        fmt.Fprintf(w, "Render page.html error: %v!", err)
    }
})

fmt.Println("Listening and serving HTTP on :9090")
http.ListenAndServe(":9090", nil)

}

Project structure: ```go |-- app/views/ |--- index.html
|--- page.html |-- layouts/ |--- footer.html |--- master.html |-- app/static/
|-- css/ |--- bootstrap.css
|-- img/ |--- gopher.png

See in "examples/gorice" folder ```

gorice example

More examples

See _examples/ for a variety of examples.

Todo

[ ] Add Partials support directory or glob [ ] Add functions support.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.