Go 1.16 推出 Embedding Files

appleboy發表於2020-12-27

原文來自:『Go 1.16 推出 Embedding Files

Go 語言官方維護團隊 rsc 之前在 GitHub Issue 上面提出要在 go command line 直接支援 Embedding Files,沒想到過沒幾個月,就直接實現出來了,並且預計在 2021 的 go 1.16 版本直接支援 embed 套件。有了這個功能,就可以將靜態檔案或專案設定檔直接包起來,這樣部署就更方便了。底下來看看官方怎麼使用。

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 了。

更多原創文章乾貨分享,請關注公眾號
  • Go 1.16 推出 Embedding Files
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章