Go 語言官方維護團隊 rsc 之前在 GitHub Issue 上面提出要在 go command line 直接支援 Embedding Files,沒想到過沒幾個月,就直接實現出來了,並且預計在 2021 的 go 1.16 版本直接支援 embed 套件。有了這個功能,就可以將靜態檔案或專案設定檔直接包起來,這樣部署就更方便了。底下來看看官方怎麼使用。
影片教學
如果對於課程內容有興趣,可以參考底下課程。
如果需要搭配購買請直接透過 FB 聯絡我,直接匯款(價格再減 100)
embed package
直接看官方給的例子:
package main
import "embed"
func main() {
//go:embed hello.txt
var s string
print(s)
//go:embed hello.txt
var b []byte
print(string(b))
//go:embed hello.txt
var f embed.FS
data, _ := f.ReadFile("hello.txt")
print(string(data))
}
可以看到關鍵字: go:embed
,透過註解就可以將靜態檔案直接使用在開發上面,另外也可以引用多個檔案或多個目錄:
package server
import "embed"
// content holds our static web server content.
//go:embed image/* template/*
//go:embed html/index.html
var content embed.FS
可以看到 go:embed
支援多個目錄,單一檔案或多個檔案都可以,假如沒有用到 embed.FS
,請在 import 時加上 _
,範例如下:
package main
import _ "embed"
func main() {
//go:embed hello.txt
var s string
print(s)
//go:embed hello.txt
var b []byte
print(string(b))
}
有了這個 Package 後,再也不需要第三方套件 Resource Embedding 了,底下來看看如何將 embed 套件整合進 Gin?
整合 Gin Framework
先假設 Gin 需要包含靜態圖片及 Template,底下是目錄結構:
├── assets
│ ├── favicon.ico
│ └── images
│ └── example.png
├── go.mod
├── go.sum
├── main.go
└── templates
├── foo
│ └── bar.tmpl
└── index.tmpl
該如何將 Template 跟 assets 目錄直接打包進 Go 呢?直接看 main.go
package main
import (
"embed"
"html/template"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
//go:embed assets/* templates/*
var f embed.FS
router := gin.Default()
templ := template.Must(template.New("").ParseFS(f, "templates/*.tmpl", "templates/foo/*.tmpl"))
router.SetHTMLTemplate(templ)
// example: /public/assets/images/example.png
router.StaticFS("/public", http.FS(f))
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
router.GET("/foo", func(c *gin.Context) {
c.HTML(http.StatusOK, "bar.tmpl", gin.H{
"title": "Foo website",
})
})
router.GET("favicon.ico", func(c *gin.Context) {
file, _ := f.ReadFile("assets/favicon.ico")
c.Data(
http.StatusOK,
"image/x-icon",
file,
)
})
router.Run(":8080")
}
開發者可以很簡單用兩行就將靜態檔案直接包進來:
//go:embed assets/* templates/*
var f embed.FS
靜態檔案的 route 可以直接透過底下設定:
// example: /public/assets/images/example.png
router.StaticFS("/public", http.FS(f))
也可以透過 ReadFile
讀取單一檔案:
router.GET("favicon.ico", func(c *gin.Context) {
file, _ := f.ReadFile("assets/favicon.ico")
c.Data(
http.StatusOK,
"image/x-icon",
file,
)
})
程式範例可以直接在這邊找到。
心得
Go 團隊真的蠻用心的,會比一些常用核心的功能納入官方維護,以保持後續的更新,有了這項功能,在 Go 的部署流程,直接可以略過靜態檔案加入 Docker 內了。未來專案有些保密檔案也可以透過此方式直接在 CI 流程內先換掉,再進行 go build 了。