A handy, fast and powerful go template engine.

Hero

Hero is a handy, fast and powerful go template engine, which pre-compiles the html templates to go code. It has been used in production environment in bthub.io.

GoDoc Go Report Card Travis CI

中文文档

Features

  • High performance.
  • Easy to use.
  • Powerful. template Extend and Include supported.
  • Auto compiling when files change.

Performance

Hero is the fastest and least-memory used among currently known template engines in the benchmark. The data of chart comes from https://github.com/SlinSo/goTemplateBenchmark. You can find more details and benchmarks from that project.

Install

go get github.com/shiyanhui/hero/hero

# Hero needs `goimports` to format the generated codes.
go get golang.org/x/tools/cmd/goimports

Usage

hero [options]

  -source string
        the html template file or dir (default "./")
  -dest string
        generated golang files dir, it will be the same with source if not set
  -extensions string
        source file extensions, comma splitted if many (default ".html")
  -pkgname template
        the generated template package name, default is template (default "template")
  -watch
        whether automatically compile when the source files change

example:
	hero -source="./"
	hero -source="$GOPATH/src/app/template" -dest="./" -extensions=".html,.htm" -pkgname="t" -watch

Quick Start

Assume that we are going to render a user list userlist.html. index.html is the layout, and user.html is an item in the list.

And assumes that they are all under $GOPATH/src/app/template

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    </head>

    <body>
        <%@ body { %>
        <% } %>
    </body>
</html>

userlist.html

<%: func UserList(userList []string, buffer *bytes.Buffer) %>

<%~ "index.html" %>

<%@ body { %>
    <% for _, user := range userList { %>
        <ul>
            <%+ "user.html" %>
        </ul>
    <% } %>
<% } %>

user.html

<li>
    <%= user %>
</li>

Then we compile the templates to go code.

hero -source="$GOPATH/src/app/template"

We will get three new .go files under $GOPATH/src/app/template, i.e. index.html.go, user.html.go and userlist.html.go.

Then we write a http server in $GOPATH/src/app/main.go.

main.go

package main

import (
    "bytes"
    "net/http"

    "app/template"
)

func main() {
    http.HandleFunc("/users", func(w http.ResponseWriter, req *http.Request) {
        var userList = []string {
            "Alice",
            "Bob",
            "Tom",
        }

        // Had better use buffer pool. Hero exports `GetBuffer` and `PutBuffer` for this.
        //
        // For convenience, hero also supports `io.Writer`. For example, you can also define
        // the function to `func UserList(userList []string, w io.Writer) (int, error)`,
        // and then:
        //
        //   template.UserList(userList, w)
        //
        buffer := new(bytes.Buffer)
        template.UserList(userList, buffer)
        w.Write(buffer.Bytes())
    })

    http.ListenAndServe(":8080", nil)
}

At last, start the server and visit http://localhost:8080/users in your browser, we will get what we want!

Template syntax

There are only nine necessary kinds of statements, which are:

  • Function Definition <%: func define %>

    • Function definition statement defines the function which represents an html file.
    • The type of the last parameter in the function defined should be *bytes.Buffer for manual buffer management or io.Writer for automatic buffer management ( note: if using io.Writer you may optionally specify return values (int, error) to handle the result of io.Writer.Write). Hero will identify the parameter name automaticly.
    • Example:
      • <%: func UserList(userList []string, buffer *bytes.Buffer) %>
      • <%: func UserList(userList []string, w io.Writer) %>
      • <%: func UserList(userList []string, w io.Writer) (int, error) %>
  • Extend <%~ "parent template" %>

    • Extend statement states the parent template the current template extends.
    • The parent template should be quoted with "".
    • Example: <%~ "index.html" >, which we have mentioned in quick start, too.
  • Include <%+ "sub template" %>

    • Include statement includes a sub-template to the current template. It works like #include in C++.
    • The sub-template should be quoted with "".
    • Example: <%+ "user.html" >, which we also have mentioned in quick start.
  • Import <%! go code %>

    • Import statement imports the packages used in the defined function, and it also contains everything that is outside of the defined function.

    • Import statement will NOT be inherited by child template.

    • Example:

      <%!
        import (
            "fmt"
            "strings"
        )
      
        var a int
      
        const b = "hello, world"
      
        func Add(a, b int) int {
            return a + b
        }
      
        type S struct {
            Name string
        }
      
        func (s S) String() string {
            return s.Name
        }
      %>
  • Block <%@ blockName { %> <% } %>

    • Block statement represents a block. Child template overwrites blocks to extend parent template.

    • Example:

      <!DOCTYPE html>
      <html>
          <head>
              <meta charset="utf-8">
          </head>
      
          <body>
              <%@ body { %>
              <% } %>
          </body>
      </html>
  • Code <% go code %>

    • Code statement states all code inside the defined function. It's just go code.

    • Example:

      <% for _, user := range userList { %>
          <% if user != "Alice" { %>
              <%= user %>
          <% } %>
      <% } %>
      
      <%
          a, b := 1, 2
          c := Add(a, b)
      %>
  • Raw Value <%==[t] variable %>

    • Raw Value statement will convert the variable to string.

    • t is the type of variable, hero will find suitable converting method by t. Candidates of t are:

      • b: bool
      • i: int, int8, int16, int32, int64
      • u: byte, uint, uint8, uint16, uint32, uint64
      • f: float32, float64
      • s: string
      • bs: []byte
      • v: interface

      Note:

      • If t is not set, the value of t is s.
      • Had better not use v, cause when t=v, the converting method is fmt.Sprintf("%v", variable) and it is very slow.
    • Example:

      <%== "hello" %>
      <%==i 34  %>
      <%==u Add(a, b) %>
      <%==s user.Name %>
  • Escaped Value <%=[t] variable %>

    • Escaped Value statement is similar with Raw Value statement, but after converting, it will be escaped it with html.EscapesString.

    • t is the same as in Raw Value Statement.

    • Example:

      <%= a %>
      <%=i a + b %>
      <%=u Add(a, b) %>
      <%=bs []byte{1, 2} %>
  • Note <%# note %>

    • Note statement add notes to the template.
    • It will not be added to the generated go source.
    • Example: <# this is just a note example>.

License

Hero is licensed under the Apache License.

Comments
  • Included template's block doesn't work

    Included template's block doesn't work

    I have included navbar.html to my layout.html and created block inside navbar.html. Then other page inherited from layout and I try to override these blocks, they don't work. Then I copied navbar and pasted inside layout it worked.

  • add new template function signature which returns []byte

    add new template function signature which returns []byte

    I use ECHO web framework ( https://echo.labstack.com ) and I also got tired of repeating the same boilerplate over and over:

    buffer := new(bytes.Buffer)
    template.SomeFunc(..., buffer)
    return echoCtx.HTMLBlob(http.StatusOK, buffer.Bytes())
    

    So I added another template function type to easily use with ECHO web framework, like this:

    return echoCtx.HTMLBlob(http.StatusOK, template.SomeFunc(...))
    
  • Non string variables don't seem to work

    Non string variables don't seem to work

    It looks like there is a bug with variables that are not of string type so for example if I type: "<%=i x %>", the code generated used a variable called buffer which wasn't defined in the generated code and causes the code build to fail. When I look at the generated code, it seems like the variable name should be _buffer instead of buffer. Am I missing something?

  • Error

    Error

    Hello! When i try to use your example, firstly I get this: Parsing... Generating... Executing goimports... Executing go vet... vet: /Users/aruslan/Projects/Golang/project1/bin/test.html.go:7:12: "html" imported but not used After that I am geeting same error from Go.

  • Using -watch, on save,

    Using -watch, on save, "no such file or directory"

    The following command works:

    hero -source="./internal/public/html" -dest="./internal/template/"

    As soon as I append watch on the end, it waits for a change in the html file as expected.

    However, when I make a change and then save the html file, I get the following:

    2020/02/19 21:56:21 stat /Users/jimbo/Documents/Dev/app/internal/public/html/body.html~: no such file or directory

    ...and it crashes.

  • one key multi type of structs

    one key multi type of structs

    Hi, I found something unusual/unique when I was creating the unit test for generated .html.go file. this generated file has been used around half a year, and no error reported since you may ask why unit test for generated file. but anyway

    there's an Args which is map[string]interface{} there are 2 html files included here. <%~ "head.html" %> inside all.html

    the generated file all.html.go, there are

    info.Args["samekey"].(strcut1).ID // from head.html
    info.Args["samekey"].(struct2).Date // from all.html
    

    I was confused, because I cannot set both struct in the same key on unit test. so, I decided to change the other key inside the second html file, and generated (html.go) it again.

  • Best way to handle Global Static Values

    Best way to handle Global Static Values

    Let's say we have a struct with some global static values and we have to send this values to all the pages, should we include this struct on each func? for example:

    template.User(GlobalStatic, UserData buffer) template.Order(GlobalStatic, OrderData buffer) template.Product(GlobalStatic, ProductData buffer) etc...

    It's this the right way?

  • Best way to handle Global Dynamic Values

    Best way to handle Global Dynamic Values

    I opened 1 month ago an issue on how to handle static global values, and now I am interested on what is the best way to handle dynamic global values (e.g. user session values ). Since I can't access the session by exposing the package inside the template, I guess the best way is to send your session each time, for example let's say I need the user session data in the heqader on each page, then I would do this:

    template.UserPage(userSessionData)
    template.HomePage(userSessionData)
    template.ContactUs(userSessionData)
    //etc.
    

    Is this the 'hero way'?

  • how to use hero template engine with iris?

    how to use hero template engine with iris?

    I want to use hero template engine with iris in my project , but i don't know which is the best way to use them, somebody could write an example ? thank you!

    iris address : https://github.com/kataras/iris/

  • Qeustion

    Qeustion

    If I use buffer as you showed in example am I going to get higher performance than using io.writer? I am willing to use io.writer since it is much convenient and requires less code.

  • Single output file

    Single output file

    Hi,

    What do you think of having a parameter to compile the views into one single .go file? Having many .go files just make harder to find the .html file in the tree.

    Thanks.

  • The term 'hero' is not recognized

    The term 'hero' is not recognized

    After hero package installation in windows 10 the 'hero' not recognized by PowerShell: hero : The term 'hero' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

  • Don't generate partial if empty.

    Don't generate partial if empty.

    If I create a partial, even though it is inlined in the file it is included in, hero will still generate an empty file like so:

    package generated
    

    It would make for cleaner output if these empty files are omitted.

  • Declaring a type in the import block of an include will duplicate that type declaration when the include is used in multiple templates.

    Declaring a type in the import block of an include will duplicate that type declaration when the include is used in multiple templates.

    I'd like to be able to declare types in my partial files.

    partial.html

    <%!
      type MyPartial struct {
          Name string
      }
    %>
    

    templateA.html

    <%: func TemplateA(data []string, buffer *bytes.Buffer) %>
    
    <%+ "partial.html" %>
    
    ...
    

    templateB.html

    <%: func TemplateB(data []string, buffer *bytes.Buffer) %>
    
    <%+ "partial.html" %>
    
    ...
    

    The generated templates, templateB.html.go and templateA.html.go will both have the MyPartial type declaration, which will cause the MyPartial redeclared in this block golang error.

    One potential solution to this issue would be to add a new syntax dedicated to type declarations. The types declared using this new syntax would only be output once.

    Let me know if there's an alternative way to accomplish this that I'm missing. I'm also willing to submit a PR if fixing this issue is non-trivial to accomplish. Thank you very much!

  • Gin-Gonic with hero example

    Gin-Gonic with hero example

    Hi everyone, I wrote code for Hero template system example and I merged it with Gin framework, I didn't see any like this in documentation, I think this can be useful for someone else. I based my code en 2 basic examples. I don't sure where post this, so I opened a issues please feel free to write any suggestion.

    @gin-gonic

    `package main

    import ( "bytes" "fmt" "ginapp/template" "io" "net/http"

    "github.com/gin-gonic/gin" )

    func main() { router := gin.Default() router.GET("/someDataFromReader", func(c *gin.Context) { var buffer bytes.Buffer var reader io.Reader contentType := "text/html , utf8"

    extraHeaders := map[string]string{
    	"accept-ranges": "bytes",
    }
    
    var userList = []string{
    	"Alice",
    	"Bob",
    	"Tom",
    }
    
    template.UserList(userList, &buffer)
    
    nRead := int64(len(buffer.Bytes()))
    reader = bytes.NewReader(buffer.Bytes())
    
    fmt.Println(nRead)
    
    c.DataFromReader(http.StatusOK, nRead, contentType, reader, extraHeaders)
    

    }) router.Run(":8080") } `

  • [improvement] html 缩进希望能和源文件一致

    [improvement] html 缩进希望能和源文件一致

    有 include 页面时,缩进表现的不好,现在貌似被 gofmt 格式化过,除了缩进还有没用的多余空行

    预期的效果,是能尽量保持 .html 的缩进

    现在的表现: userlist.html.go

    	for _, user := range userList {
    		buffer.WriteString(`
            <ul>
                `)
    		buffer.WriteString(`<li>
        `)
    		hero.EscapeHTML(user, buffer)
    		buffer.WriteString(`
    </li>
    `)
    		buffer.WriteString(`
            </ul>
        `)
    	}
    

    Response

            <ul>
                <li>
        Alice
    </li>
    
            </ul>
        
            <ul>
                <li>
        Bob
    </li>
    
            </ul>
        
            <ul>
                <li>
        Tom
    </li>
    
            </ul>
    
A Handy FieldBuilder Template for uber-go/zap

zap-fieldbuilder-template A Handy Generic Logging FieldBuilder Template around uber-go/zap. You can check this tiny blog for further information ?? Wh

Dec 16, 2021
The world’s most powerful template engine and Go embeddable interpreter.
The world’s most powerful template engine and Go embeddable interpreter.

The world’s most powerful template engine and Go embeddable interpreter

Dec 23, 2022
Simple and fast template engine for Go

fasttemplate Simple and fast template engine for Go. Fasttemplate performs only a single task - it substitutes template placeholders with user-defined

Dec 30, 2022
The powerful template system that Go needs

Plush Plush is the templating system that Go both needs and deserves. Powerful, flexible, and extendable, Plush is there to make writing your template

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

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

Dec 25, 2022
Simple system for writing HTML/XML as Go code. Better-performing replacement for html/template and text/template

Simple system for writing HTML as Go code. Use normal Go conditionals, loops and functions. Benefit from typing and code analysis. Better performance than templating. Tiny and dependency-free.

Dec 5, 2022
A template to build dynamic web apps quickly using Go, html/template and javascript
A template to build dynamic web apps quickly using Go, html/template and javascript

gomodest-template A modest template to build dynamic web apps in Go, HTML and sprinkles and spots of javascript. Why ? Build dynamic websites using th

Dec 29, 2022
Wrapper package for Go's template/html to allow for easy file-based template inheritance.

Extemplate Extemplate is a small wrapper package around html/template to allow for easy file-based template inheritance. File: templates/parent.tmpl <

Dec 6, 2022
Made from template temporalio/money-transfer-project-template-go
Made from template temporalio/money-transfer-project-template-go

Temporal Go Project Template This is a simple project for demonstrating Temporal with the Go SDK. The full 20 minute guide is here: https://docs.tempo

Jan 6, 2022
Go-project-template - Template for a golang project

This is a template repository for golang project Usage Go to github: https://git

Oct 25, 2022
Go-api-template - A rough template to give you a starting point for your API

Golang API Template This is only a rough template to give you a starting point f

Jan 14, 2022
Api-go-template - A simple Go API template that uses a controller-service based model to build its routes

api-go-template This is a simple Go API template that uses a controller-service

Feb 18, 2022
HTML template engine for Go

Ace - HTML template engine for Go Overview Ace is an HTML template engine for Go. This is inspired by Slim and Jade. This is a refinement of Gold. Exa

Jan 4, 2023
Jet template engine

Jet Template Engine for Go Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast. simple and familiar synt

Jan 4, 2023
A complete Liquid template engine in Go
A complete Liquid template engine in Go

Liquid Template Parser liquid is a pure Go implementation of Shopify Liquid templates. It was developed for use in the Gojekyll port of the Jekyll sta

Dec 15, 2022
gtpl is a template engine for glang

gtpl 使用必读 gtpl is a HTML template engine for golang gtpl 是一个 go 语言模板引擎,它能以极快的速度进行模板语法分析。相比 go 语言官方库 html/template,gtpl 的语法有着简练、灵活、易用的特点。

Nov 28, 2022
This my project template for making fiber with SSR taste by empowered mustache engine.

SSR-FIBER-TEMPLATE This my project template for making fiber with SSR taste by empowered mustache engine. Folder Hierarchy Name Description configs Co

May 9, 2022
Package damsel provides html outlining via css-selectors and common template functionality.

Damsel Markup language featuring html outlining via css-selectors, extensible via pkg html/template and others. Library This package expects to exist

Oct 23, 2022
A sane and simple Go REST API template.

Gosane ??‍♀️ A sane and simple Go REST API template. Clone me and edit me to fit your usecase. What is Gosane? Gosane is a cloneable API template to g

Dec 7, 2022