Go:嵌入二进制文件的模板返回空白页面

huangapple go评论73阅读模式
英文:

Go: Templates Embedded in Binary Return Blank Page

问题

尝试将我的 Golang HTML 模板从文件移动到使用 embed

以下是代码示例:

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

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

	// 从 layouts/ 和 includes/ 目录生成模板映射

	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
}

在调试器中确认所有模板都不包含错误并且具有相应的内容。其他嵌入的文件(如静态资源)正常工作并正常提供服务。甚至从数据库加载的其他模板也正常工作。只有使用 embed 的模板最终为空白。

有什么提示可以解释这里发生了什么吗?谢谢!

编辑:完整示例:

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()

	// 从 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")

	// 从真实文件系统加载相同的模板
	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 正常工作,但 /embed 显示为空白。

英文:

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(&quot;templates/layouts/*.tmpl&quot;)
if err != nil {
panic(err.Error())
}
includes, err := filepath.Glob(&quot;templates/includes/*.tmpl&quot;)
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) + &quot;: &quot; + 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, &quot;templates/layouts&quot;)
if err != nil {
panic(err.Error())
}
for _, layout := range layouts {
embeddedTemplate, err := template.ParseFS(f, &quot;templates/layouts/&quot;+layout.Name(), &quot;templates/includes/base.tmpl&quot;)
if err != nil {
log.Println(err)
}
r.Add(layout.Name(), embeddedTemplate)
log.Println(layout.Name() + &quot; loaded&quot;)
}
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 (
&quot;embed&quot;
&quot;html/template&quot;
&quot;log&quot;
&quot;path/filepath&quot;
&quot;github.com/gin-contrib/multitemplate&quot;
&quot;github.com/gin-gonic/gin&quot;
)
//go:embed templates/*
var f embed.FS
func main() {
router := gin.Default()
router.HTMLRender = loadTemplates()
router.GET(&quot;/embed&quot;, HomeHandlerEmbed(router))
router.GET(&quot;/file&quot;, HomeHandlerFile(router))
router.Run(&quot;:8080&quot;)
}
func loadTemplates() multitemplate.Render {
r := multitemplate.New()
//load same template from embed FS
embeddedTemplate, err := template.ParseFS(f, &quot;templates/layouts/home.tmpl&quot;, &quot;templates/includes/base.tmpl&quot;)
if err != nil {
log.Println(err)
}
r.Add(&quot;homeEmbed.tmpl&quot;, embeddedTemplate)
log.Println(&quot;homeEmbed.tmpl&quot; + &quot; loaded from embed FS&quot;)
// load same template from real file system
layoutsFile, err := filepath.Glob(&quot;templates/layouts/*.tmpl&quot;)
if err != nil {
panic(err.Error())
}
includes, err := filepath.Glob(&quot;templates/includes/*.tmpl&quot;)
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) + &quot;: &quot; + files[0])
}
return r
}
func HomeHandlerEmbed(r *gin.Engine) gin.HandlerFunc {
return gin.HandlerFunc(func(c *gin.Context) {
c.HTML(200, &quot;homeEmbed.tmpl&quot;, nil)
})
}
func HomeHandlerFile(r *gin.Engine) gin.HandlerFunc {
return gin.HandlerFunc(func(c *gin.Context) {
c.HTML(200, &quot;home.tmpl&quot;, nil)
})
}

templates/includes/base.tmpl

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
{{template &quot;head&quot; .}}
&lt;/head&gt;
&lt;body&gt;
{{template &quot;body&quot; .}}
&lt;/body&gt;
&lt;/html&gt;

templates/layouts/home.tmpl

{{define &quot;head&quot;}}&lt;title&gt;Test&lt;/title&gt;{{end}}
{{define &quot;body&quot;}}
Body
{{end}}

/file works fine, /embed comes up blank

答案1

得分: 0

loadTemplates()函数中,只需修复这一行代码:

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

在你的示例中,模板的顺序将按照以下顺序呈现:

  • 第一个:"templates/layouts/home.tmpl"
  • 第二个:"templates/includes/base.tmpl"

但是,如果我理解正确,对于函数template.ParseFS来说,模板的顺序是重要的,因为base.tmpl将包含在所有模板中。

函数template.ParseFS会在进程中读取模板并尝试生成它们。

英文:

In function loadTemplates() just fix this line:

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

In your example patterns will be presented in this sequence:

  • first: &quot;templates/layouts/home.tmpl&quot;
  • second: &quot;templates/includes/base.tmpl&quot;

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.

huangapple
  • 本文由 发表于 2022年8月22日 07:29:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/73438924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定