Home > OS >  Go: Templates Embedded in Binary Return Blank Page
Go: Templates Embedded in Binary Return Blank Page

Time:08-26

Trying to move my golang html templates from files to using embed

Works fine:

func loadTemplates() multitemplate.Render {
    r := multitemplate.New()

    layouts, err := filepath.Glob("templates/layouts/*.tmpl")
    if err != nil {
        panic(err.Error())
    }

    includes, err := filepath.Glob("templates/includes/*.tmpl")
    if err != nil {
        panic(err.Error())
    }

    // Generate our templates map from our layouts/ and includes/ directories
    for _, layout := range layouts {
        files := append(includes, layout)
        r.Add(filepath.Base(layout), template.Must(template.ParseFiles(files...)))
        log.Println(filepath.Base(layout)   ": "   files[0])
    }

    return r
}

Very similar code returns blank page, no errors:


//go:embed templates/*
var f embed.FS


func loadTemplates() multitemplate.Render {
    r := multitemplate.New()

    // Generate our templates map from our layouts/ and includes/ directories

    layouts, err := embed.FS.ReadDir(f, "templates/layouts")
    if err != nil {
        panic(err.Error())
    }

    for _, layout := range layouts {
        embeddedTemplate, err := template.ParseFS(f, "templates/layouts/" layout.Name(), "templates/includes/base.tmpl")
        if err != nil {
            log.Println(err)
        }
        r.Add(layout.Name(), embeddedTemplate)
        log.Println(layout.Name()   " loaded")
    }

    return r
}

I confirmed in the debugger that all templates contain no errors and their respective content. Other embedded files such as static assets work fine and get served ok. Even other templates loaded from a database work fine. Just those from embed end up blank.

Any hints what's happening here? Thanks!

Edit: Full example:

main.go

package main

import (
    "embed"
    "html/template"
    "log"
    "path/filepath"

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

//go:embed templates/*
var f embed.FS

func main() {

    router := gin.Default()
    router.HTMLRender = loadTemplates()

    router.GET("/embed", HomeHandlerEmbed(router))
    router.GET("/file", HomeHandlerFile(router))

    router.Run(":8080")

}

func loadTemplates() multitemplate.Render {
    r := multitemplate.New()

    //load same template from embed FS
    embeddedTemplate, err := template.ParseFS(f, "templates/layouts/home.tmpl", "templates/includes/base.tmpl")
    if err != nil {
        log.Println(err)
    }
    r.Add("homeEmbed.tmpl", embeddedTemplate)
    log.Println("homeEmbed.tmpl"   " loaded from embed FS")

    // load same template from real file system
    layoutsFile, err := filepath.Glob("templates/layouts/*.tmpl")
    if err != nil {
        panic(err.Error())
    }

    includes, err := filepath.Glob("templates/includes/*.tmpl")
    if err != nil {
        panic(err.Error())
    }

    for _, layout := range layoutsFile {
        files := append(includes, layout)
        r.Add(filepath.Base(layout), template.Must(template.ParseFiles(files...)))
        log.Println(filepath.Base(layout)   ": "   files[0])
    }

    return r

}

func HomeHandlerEmbed(r *gin.Engine) gin.HandlerFunc {

    return gin.HandlerFunc(func(c *gin.Context) {

        c.HTML(200, "homeEmbed.tmpl", nil)

    })
}

func HomeHandlerFile(r *gin.Engine) gin.HandlerFunc {

    return gin.HandlerFunc(func(c *gin.Context) {

        c.HTML(200, "home.tmpl", nil)

    })
}

templates/includes/base.tmpl

<!DOCTYPE html>
<html>
<head>
{{template "head" .}}
</head>
<body>

    {{template "body" .}}
  
</body>
</html>

templates/layouts/home.tmpl

{{define "head"}}<title>Test</title>{{end}}
{{define "body"}}

Body

{{end}}

/file works fine, /embed comes up blank

CodePudding user response:

In function loadTemplates() just fix this line:

embeddedTemplate, err := template.ParseFS(f, "templates/includes/base.tmpl", "templates/layouts/home.tmpl")

In your example patterns will be presented in this sequence:

  • first: "templates/layouts/home.tmpl"
  • second: "templates/includes/base.tmpl"

But if I understood correctly, the sequence of patterns is important for the function template.ParseFS, because base.tmpl will be included in all you templates.

The function template.ParseFS reads the templates in the process and tries to generate them.

  • Related