シングルバイナリーがメリットと言われてる Go 言語ですが、HTML などのテンプレートはそのバイナリは埋め込むことができませんでした。
(hugo のようにファイルを生成するツールがあるので、無理くり、埋め込むことはできたんだと思いますが。。)
追記(2020/03/10): こちらの YouTube 動画 にて、1.16 より前の静的ファイルの埋め込み方法が解説されています。(ざっくりと、var embedData = []byte("静的ファイルの中身")
が定義された Go ファイルを作成して build する。なるほどですね。)
ただ、Go 1.16 から go:embed
を使うことで、めっちゃ簡単に埋め込むことができるようになりました!!
インポートした後は、これまで通り http/template
が使えます!
めっちゃ便利なので、おすすめです。
以下、ざっくりとまとめです。
参考
https://golang.org/pkg/embed/
https://golang.org/pkg/html/template/
フォルダ配下全てを読み込み
下記のように書くことで、templates
フォルダ配下のファイルを読み込みできます。
その後は、f
を経由してアクセスできるようになります。
//go:embed templates
var f embed.FS
そう!これだけ!
読み込んだテンプレートを使う
template.ParseFS()
を使って、インポートした特定の HTML を呼び出します。
tmpl, _ := template.ParseFS(f, "templates/index.html")
あとは、これまで通り Execute()
で http.ResponreWriter
に書き込み
// ここはこれまで通り
err := tmpl.Execute(w, "Second Page")
めっちゃ簡単!!
コード全体
package main
import (
"embed"
"html/template"
"log"
"net/http"
)
//go:embed templates
var f embed.FS
func index(w http.ResponseWriter, r *http.Request) {
tmpl, _ := template.ParseFS(f, "templates/index.html")
type Post struct {
PageTitle string
PageContent string
}
// Struct データを渡してみる
err := tmpl.Execute(w, &Post{PageTitle: "Index Page", PageContent: "トップページのコンテンツ"})
if err != nil {
log.Println(err)
}
}
func second(w http.ResponseWriter, r *http.Request) {
// base.html ばベースのテンプレートになるので、同時にパース
tmpl, _ := template.ParseFS(f, "templates/second.html", "templates/base.html")
// シンプルにテキスト文字列を渡してみる
err := tmpl.Execute(w, "Second Page")
if err != nil {
log.Println(err)
}
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/second", second)
log.Println("listening ... ")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
確認①: テンプレートにデータを渡すことができる
index.html
ページでは渡された struct データを受け取り、使うことができます
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name={{.}}>
<title>{{ .PageTitle }}</title>
</head>
<body>
<h1> {{ .PageContent }}</h1>
</body>
</html>
確認②: ベーステンプレートを使うこともできる
{{ define "base" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ . }}</title>
</head>
<body>
{{template "content" . }}
</body>
</html>
{{ end }}
このベーステンプレートを使って、second.html
を書く
{{ template "base" . }}
{{ define "content" }}
<h1>Welcome to Second Page</h1>
{{ end }}