Jet template engine

Jet Template Engine for Go

Build Status Build status Join the chat at https://gitter.im/CloudyKit/jet

Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast.

  • simple and familiar syntax
  • supports template inheritance (extends) and composition (block/yield, import, include)
  • descriptive error messages with filename and line number
  • auto-escaping
  • simple C-like expressions
  • very fast execution – Jet can execute templates faster than some pre-compiled template engines
  • very light in terms of allocations and memory footprint

v6

Version 6 brings major improvements to the Go API. Make sure to read through the breaking changes before making the jump.

Docs

Example application

An example to-do application is available in examples/todos. Clone the repository, then (in the repository root) do:

  $ cd examples/todos; go run main.go

IntelliJ Plugin

If you use IntelliJ there is a plugin available at https://github.com/jhsx/GoJetPlugin. There is also a very good Go plugin for IntelliJ – see https://github.com/go-lang-plugin-org/go-lang-idea-plugin. GoJetPlugin + Go-lang-idea-plugin = happiness!

Contributing

All contributions are welcome – if you find a bug please report it.

Contributors

  • José Santos (@jhsx)
  • Daniel Lohse (@annismckenzie)
  • Alexander Willing (@sauerbraten)
Comments
  • Add ability to use an http.FileSystem for looking up templates

    Add ability to use an http.FileSystem for looking up templates

    Together with a tool like vfsgen this can be used to embed the templates into the compiled go binary. This makes deployments simpler and faster but should be used in conjunction with the development mode and a stubbed (read: nil) http.FileSystem.

  • Pass new scope to yield and include

    Pass new scope to yield and include

    I'm trying to imitate some of the approaches other frameworks take to provide a common library of reusable parts for forms. The {{import "form_theme_bootstrap.jet" }} and the {{yield}} directive are good building blocks to achieve that. The problem arrises when trying to pass local variables to use when yielding, for example, an input-field block in the sense that it's not possible (at least I don't see a way).

    Let me explain with some code:

    <!-- file: "form_theme_bootstrap.jet" -->
    {{block input-field}}
      <div class="{{container_class}} {{if has_error}}invalid{{else}}valid{{end}}">
        <input id="{{name}}" name="{{name}}" value="{{value}}" />
        {{if has_error}}
          <div class="form_error">{{error}}</div>
        {{end}}
      </div>
    {{end}}
    
    <!-- file: "user_form_edit.jet" -->
    {{import "form_theme_bootstrap.jet"}}
    
    <form>
      <!-- not sure how passing a hash/map of local variables would work  -->
      {{yield input-field { name: "firstname", value: .Firstname, has_error: errs.HasErrorFor("Firstname"), error: errs.ErrorFor("Firstname"), container_class: "" }  }}
    </form>
    

    Do you see what I'm trying to do? Having a way to construct a map on the fly in the template would be really great, that way I could use that as the context for the yield.

    Thanks again for all the hard work and this great library!

  • include & extend don't handle absolute paths correctly

    include & extend don't handle absolute paths correctly

    Assuming I have a template at foo/baz.jet, {{ include "foo/bar.jet" }} will make resolveNameSibling try to resolve foo/foo/bar.jet before resolving foo/bar.jet: https://github.com/CloudyKit/jet/blob/33cfc27b3e00072655fdb3af24c3253ea5bffb8f/template.go#L153

    name will be "foo/bar.jet", sibling will be "foo/baz.jet".

    I would like to simplify template resolving & loading and could fix this issue at the same time. Seeing as we are making breaking changes with v3 anyway, I would like to make jet handle paths like most software does:

    • ./asd.jet, asd.jet, ../asd.jet will be treated as relative paths and will be resolved relative to the current template's path
    • /foo.jet, /foo/bar.jet will be treated as absolute paths and will be looked up directly in the templates cache and/or the loader, without using the current template's path

    Do you want me to proceed with this? Did I miss something?

  • Regression: Ranging over slice from Fast Function

    Regression: Ranging over slice from Fast Function

    I've observed a regression caused by https://github.com/CloudyKit/jet/commit/6d666f94dfe73004a23e8e41d7532ac8602c9132 (#112)

    Summary

    For this template:

    {{sorted := SortApples(myApples)}}
    {{range i, apple := sorted}}
    	{{i}}: {{apple.GetFlavor()}}
    {{end}}
    

    (Where SortApples is a fast function aka jet.Func.)

    Jet was able to range over the returned slice up until https://github.com/CloudyKit/jet/commit/6d666f94dfe73004a23e8e41d7532ac8602c9132 at which point the template execution would error with: there is no field or method "GetFlavor" in main.Apple

    Example Project

    https://github.com/tooolbox/jet-example has two branches:

    • v2.1.2 (working)
    • v2.1.3-6d666f94dfe7 (broken)

    I understand we're now going for a v3 with these commits, so breaking changes might be expected, but this seems like it would hurt fast functions a lot.

    cc @sauerbraten

  • Variable in block parameter

    Variable in block parameter

    I have this

    Go code:

    ...
    func theaterPage(client *gin.Context) {
    	channel := client.Param("channel") // is just a string like "Left4Bot"
    	view, err := views.GetTemplate("theater.tpl.html")
    	if err != nil {
    		return
    	}
    	view.Execute(client.Writer, jet.VarMap{
    		"ChannelName": reflect.ValueOf(channel),
    	}, nil)
    }
    

    My block:

    {{block embedPlayer(channel="toby3d", autoplay=false)}}
    	<iframe src="//www.hitbox.tv/#!/embed/{{ channel }}?autoplay={{ autoplay }}" width="360" height="640" frameborder="0" allowfullscreen></iframe>
    {{end}}
    

    My template:

    {{ block body() }}
    	<main>
    		{{ yield embedPlayer(channel=.ChannelName, autoplay=true) }}
    	</main>
    {{ end }}
    

    And this does not work. How can I implement a variable in a block parameter?

  • Fix inconsistency with add operator, Added switch/case, Added default block values, Filter block with format function

    Fix inconsistency with add operator, Added switch/case, Added default block values, Filter block with format function

    Add: "2" + 1 - output: 3 1 + "2" - output: 3 "2" + "2" - output: 4 "2" + "2z" - output: 22z

    Switch/Case with empty case as default : {{ switch power }} {{ case 10 }} Value is 10 {{ end }} {{ case }} This is default case {{ end }} {{ end }}

    Default block:

    • Example 1: {{ Size = 10 }} {{ default }} {{ Size = 20 }} {{ end }} Size is {{ Size }} cm output : Size is 10 cm

    • Example 2: {{ default }} {{ Size = 20 }} {{ end }} Size is {{ Size }} cm output : Size is 20 cm

    Filter block with format function: {{ filter format("<-- %v -->") }} This is formatted text {{ end }} output: <-- This is --> <-- formatted text -->

  • how to call template function?

    how to call template function?

    I use a template variable to send a function, how to call it in the template?

    func Full() string {
    	return "ok"
    }
    
    data := make(map[string]interface{})
    data["Full"]= Full
    
  • Allow accessing struct fields using lower case names

    Allow accessing struct fields using lower case names

    @annismckenzie Curious your thoughts about this - internally my structs have a lot of *string, *int, *bool, etc. where the values can be nil if not set explicitly. In Jet if a structure has a field and its value is nil then it appears to be the same as it not existing -- https://github.com/CloudyKit/jet/blob/master/eval.go#L1111

    From a templating perspective I'd think they would be treated as safe values such as "", 0, false, etc. if it exists unless I'm explicitly comparing them with nil with isset. If I made a change to differentiate between a field that doesn't exist and a field that does exist but it set to nil, is that a change you would be interested in?

    I was also thinking that using field tags to have a preferred name for struct fields (like encoding/json does) so that its not so obvious that Golang is involved in rendering the template or to obfuscate where the value might be coming from. It looks like there is just couple places in eval.go where a change would be needed to implement that. Would you be interested in that change if I got it working?

  • Clean up template loading

    Clean up template loading

    This fixes #127 (paths in templates will be handled as described there) and #128.

    Breaking changes:

    • OSFileSystemLoader only supports a single directory instead of multiple
    • the AddPath and AddGopathPath functions were removed
    • ~~Loader.Exists no longer returns the "real" file name~~
    • after include or extends, relative paths will no longer be looked up as absolute paths (see #127)

    I removed the ability to have multiple directories managed by a single OSFileSystemLoader becaue of #128, and because I feel like

    1. most users will have all templates in a single directory, organized into subdirectories there,
    2. with the new handling of relative paths, the top directory name will appear in paths less often, and
    3. you can always use loaders.Multi to get back the functionality a single OSFileSystemLoader provided before

    I added a note to loaders.Multi warning that lookup order depends on the order in which loaders are passed in during instantiation.

  • Revamp Documentation

    Revamp Documentation

    While the Jet Wiki here on GitHub has some useful information and examples, it is not easy to use as a reference document. I propose this gets cleaned up!

    1. In a Godoc, all objects and methods are laid out in a row with the exact signatures, with an index to find what you need. With Jet's wiki, the important syntax examples or function names are buried in paragraphs of tutorial-style explanation.
    2. The titles of each page are not clearly representative of their content. For example, "Advanced" specifically contains interfaces you can implement to increase speed or customize rendering output. When answering the question "What's that piece of syntax?" the answer may be in the "Expressions" page or maybe the "Jet template syntax" page, or maybe some other page entirely.
    3. Some commands do not have precisely defined behavior, but are only explained through examples. The best example of this is yield.
    4. The documentation is sprinkled with "new in v2". Now that v2 has been out for some time and is likely the standard, this commentary could be removed.

    I would love to be able to open a PR on the Wiki, but GitHub doesn't seem to support that 😞

  • dump() built-in function (#111)

    dump() built-in function (#111)

    The following is - perhaps naive? - attempt to satisfy requirement described in issue #187. Let me know what you think - Jet internals are mystery to me, at least for now.

    To be honest, I am not sure why comparison against master contains also changes implemented by 4beb91506060bd8900ec0f7d42e401d21300350f and f67928da339229e4ccb9b198a6428b8f077cf1c9 - that is confusing.

    Regards,

    Jan

  • Pipe command type string is not func

    Pipe command type string is not func

    When I do this

    ... | money("$") | ....

    I get

    pipe command "money(\"$\")" type string is not func

    with

    .AddGlobalFunc("money", func(a jet.Arguments) reflect.Value { a.RequireNumOfArguments("money", 1, 2)

    Is there an example on how to do this?

    The builtin "repeat(2)" is doing this for example.

  • Prevent cyclic imports

    Prevent cyclic imports

    Cyclic imports add an infinite loop in the latest jet version.

    Edit:

    This:

    <!-- file test1.html -->
    {{ import "./test2.html" }}
    <p> hi </p>
    
    <!-- file test2.html -->
    {{ import "./test1.html" }}
    <p> hello </p>
    
    

    Makes jet go into an infinite loop when executing one of these templates.

  • go 1.17.7 new issue

    go 1.17.7 new issue

    Hi there, please consider following:

    type Mode uint8
    
    const (
    	Reserved Mode = iota
            Foo
            Bar
    )
    
    func (m Mode) String() string {
    	switch m {
    	case Foo:
    		return "Foo"
    	case Bar:
    		return "Bar"
           default:
    		return "Reserved"
    	}
    }
    

    For golang < 1.17.7 I was using {{ .Mode }} and it was displayed as 0, 1, 2 Now it is displayed as Reserved, Foo, Bar.

    So Stringer interface somehow kicks in.

    There is easy workaround, but I just want to know if there is need to adjust Jet or file an issue to golang directly.

    Thanks and all the best

  • Put back YieldTemplate

    Put back YieldTemplate

    I put back YieldTemplate which was removed earlier. I am using it in my code to "insert" template files. Please put it back. Thank you very much in advance.

  • Unable to include - template could not be found

    Unable to include - template could not be found

    I'm sure this is a stupidly simple problem - but I'm staring at it and just can't see what is going on!

    Views are in a folder two levels below the executable (in www/views) and jet is configured like this:

    engine = jet.New("www/views", ".jet")

    I have a template www/views/register.jet that works just fine, with the page displayed. I then add another template to the folder 'header.jet' and add the following to the top of register.jet

    {{ include "./header.jet" }}

    But if I reload the page, I get an error:

    Jet Runtime Error ("/register":1): template /header.jet could not be found

    I have tried various things such as addint the path, such as www/views/header.jet but cannot get it to work.

    Thanks for any thoughts..

  • Adding support for Go 1.16's FS interface

    Adding support for Go 1.16's FS interface

    Go 1.16 introduces the fs package and a FS interface. Implementing a Jet loader for this seems like an ideal use case. Are there any plans for this, would it be easy?

    EDIT: actually, maybe it is as simple as this?

    type StdFileSystemLoader struct{ fs.FS }
    
    func (l StdFileSystemLoader) Open(templatePath string) (io.ReadCloser, error) {
    	return l.FS.Open(templatePath)
    }
    
    func (l StdFileSystemLoader) Exists(templatePath string) bool {
    	_, err := l.Open(templatePath)
    	return err == nil && !os.IsNotExist(err)
    }
    
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
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
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
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
A handy, fast and powerful go template engine.
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 environme

Dec 27, 2022
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
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
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
The mustache template language in Go

Overview mustache.go is an implementation of the mustache template language in Go. It is better suited for website templates than Go's native pkg/temp

Dec 22, 2022
Useful template functions for Go templates.

Sprig: Template functions for Go templates The Go language comes with a built-in template language, but not very many template functions. Sprig is a l

Jan 4, 2023
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