通过 go embed.FS 将 gin 模板及静态资源文件打包进二进制程序

发布时间: 2022-05-18 13:38:02 作者: 大象笔记

使用 gin 写网站会涉及到大量的外部文件:

发布时,除了要将编译好的二进制文件上传到服务器,还需要将上面提到的三类文件同步到二进制文件所在的目录。这样有两个弊端:

embed 打包

go 1.16 引入的新特性 embed 支持将这些外部文件打包入二进制文件。

而且 gin 也支持了 embed,配置起来就更方便了。

首先需要过一遍 go embed 的官方文档,否则 gin 里的 embed 代码不容易理解。

template 及 static 文件打包

main.go

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

func main() {
	...

	r := gin.Default()

	// apply i18n middleware
	r.Use(i18n.GinI18nLocalize())

	// 自定义模板函数
	funcMap := template.FuncMap{
		"UnescapeHTML": utils.UnescapeHTML,
		"Localize":     ginI18n.GetMessage,
	}

	// embed files
	tmpl := template.New("").Funcs(funcMap)
	tmpl = template.Must(tmpl.ParseFS(f, "templates/*.html"))
	r.SetHTMLTemplate(tmpl)

	fp, _ := fs.Sub(f, "public")
	r.StaticFS("/public", http.FS(fp))

	...
}

模板函数不要忘了配置,否则会报错,例如:

panic: template: article.html:6: function "Localize" not defined

i18n 翻译文件打包

i18n.go

gin i18n 里内置了 embed 的支持,修改一下 loader 即可。

注意,对于 sub package 中的 embed directive,路径是相对于代码文件的,而不是项目根目录。 例如,i18n.go 平级下有个 lang 目录,里面存放了翻译文件。

import (
	"embed"
	ginI18n "github.com/gin-contrib/i18n"
)

//go:embed lang/*
var fs embed.FS

func GinI18nLocalize() gin.HandlerFunc {
	return ginI18n.Localize(
		ginI18n.WithBundle(&ginI18n.BundleCfg{
			RootPath:         "./lang",
			AcceptLanguage:   []language.Tag{language.Chinese, language.English},
			DefaultLanguage:  language.Chinese,
			FormatBundleFile: "toml",
			UnmarshalFunc:    toml.Unmarshal,
			Loader:           &ginI18n.EmbedLoader{fs},
		}),
	)
}

参考

我是一名山东烟台的开发者,联系作者