Skip to content

Instantly share code, notes, and snippets.

@robvdl
Last active March 7, 2024 19:43
Show Gist options
  • Save robvdl/04dba3945e7949727085a37f53190124 to your computer and use it in GitHub Desktop.
Save robvdl/04dba3945e7949727085a37f53190124 to your computer and use it in GitHub Desktop.
Setting up Pongo2 with Echo v4
package web
import (
"io"
"github.com/flosch/pongo2/v6"
"github.com/labstack/echo/v4"
"github.com/spf13/viper"
)
// RenderOptions is used to configure the renderer.
type RenderOptions struct {
TemplateDir string
TemplateSet *pongo2.TemplateSet
ContentType string
}
// Pongo2Render is a custom Echo template renderer using Pongo2.
type Pongo2Render struct {
Options *RenderOptions
}
// NewRender creates a new Pongo2Render instance with custom Options.
func NewRender(options RenderOptions) (*Pongo2Render, error) {
// If TemplateSet is nil construct a new TemplateSet for TemplateDir.
if options.TemplateSet == nil {
loader, err := pongo2.NewLocalFileSystemLoader(options.TemplateDir)
if err != nil {
return nil, err
}
options.TemplateSet = pongo2.NewSet(options.TemplateDir, loader)
options.TemplateSet.Debug = viper.GetBool("debug")
}
render := &Pongo2Render{Options: &options}
return render, nil
}
// DefaultRender creates a Pongo2Render instance with default options.
func DefaultRender() (*Pongo2Render, error) {
return NewRender(RenderOptions{
TemplateDir: viper.GetString("template_dir"),
TemplateSet: nil,
ContentType: echo.MIMETextHTMLCharsetUTF8,
})
}
// Render is an interface function that renders a Pongo2 template as an HTML response.
func (p *Pongo2Render) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
template, err := p.Options.TemplateSet.FromCache(name)
if err != nil {
return err
}
c.Response().Header().Set(echo.HeaderContentType, p.Options.ContentType)
return template.ExecuteWriter(data.(pongo2.Context), w)
}
@robvdl
Copy link
Author

robvdl commented Jul 3, 2023

This is a code snippet for setting up Pongo2 as the template renderer in Echo. It is also using viper for config.

@robvdl
Copy link
Author

robvdl commented Jul 3, 2023

If e.Debug is true (were e is the Echo app), then it will not use a template cache. This is great for development as you can make changes to templates and not have to restart the app.

In production however, when e.Debug is false, it will use a template cache. In this mode, the first time a template is loaded from disk and compiled, it caches the compiled template. So any changes to the template on disk thereafter, requires restarting of the application as the app won't reload it. This is suitable for production but not development.

@robvdl
Copy link
Author

robvdl commented Jul 3, 2023

Also this probably should come with a "how to use", here goes:

e := echo.New()
e.Debug = viper.GetBool("debug")

// Setup the Pongo2 renderer
render, err := DefaultRender()
if err != nil {
	// handle or return error (e.g. template dir does not exist could return an error)
}
e.Renderer = render

// Start Echo
e.Logger.Fatal(e.Start(":8080"))

@robvdl
Copy link
Author

robvdl commented Jul 4, 2023

The reason I am using TemplateSet actually originated in my pongo2gin repo on Gitlab (gitlab.com/go-box/pongo2gin), a contributor needed this and added support for template sets. I since cleaned it up, refactored it, and translated the code to use Echo instead of Gin.

You may notice it automatically creates a TemplateSet based on the template dir if TemplateSet was nil. Otherwise it will use the TemplateSet you pass in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment