Go Bindata 内嵌静态资源


原文链接: Go Bindata 内嵌静态资源

使用 Go 开发应用的时候,有时会遇到需要读取静态资源的情况。比如开发 Web 应用,程序需要加载模板文件生成输出的 HTML。在程序部署的时候,除了发布应用可执行文件外,还需要发布依赖的静态资源文件。这给发布过程添加了一些麻烦。既然发布单独一个可执行文件是非常简单的操作,就有人会想办法把静态资源文件打包进 Go 的程序文件中。下面就来看一些解决方案:
go-bindata

安装 go-bindata:

go get -u github.com/jteeuwen/go-bindata/...

注意: go get 地址最后的三个点 ...。这样会分析所有子目录并下载依赖编译子目录内容。go-bindata 的命令工具在子目录中。(还要记得把 $GOPATH/bin 加入系统 PATH)。

生成命令工具 go-bindata

go-bindata -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/...

-o 输出文件到 app/asset/asset.go,
-pkg=asset 指定生成的包名 ,
然后是需要打包的目录,三个点...包括所有子目录。这样就可以把所有相关文件打包到 asset.go 且开头是 package asset 保持和目录一致。

使用静态文件的代码:

dirs := []string{"source", "theme", "doc"} // 设置需要释放的目录

for _, dir := range dirs {

// 解压dir目录到当前目录
if err := asset.RestoreAssets("./", dir); err != nil {
    isSuccess = false
    break
}

}
if !isSuccess {

for _, dir := range dirs {
    os.RemoveAll(filepath.Join("./", dir))
}

}

asset.go 内的静态内容还是根据实际的目录位置索引。所以我们可以直接通过目录或者文件地址去操作。

-debug 开发模式

go-bindata 支持开发模式,即不嵌入静态内容,只生成操作方法到输出的 go 代码中,如:

go-bindata -debug -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/...

-debug 参数开启开发模式。生成的代码会直接去读取静态文件到内存,而不是编码到代码中。代码文件更小,你更快速的编写业务逻辑。

// -pkg=asset, 打包的包名是 asset
bytes, err := asset.Asset("theme/default/post.html")    // 根据地址获取对应内容
if err != nil {
    fmt.Println(err)
    return
}
t, err := template.New("tpl").Parse(string(bytes))      // 比如用于模板处理
fmt.Println(t, err)

http.FileSystem

http.FileSystem 是定义 HTTP 静态文件服务的接口。go-bindata 的第三方包 go-bindata-assetfs 实现了这个接口,支持 HTTP 访问静态文件目录的行为。以我们上面编译好的 asset.go 为例:

import (
	"net/http"

	"github.com/elazarl/go-bindata-assetfs"
	"github.com/go-xiaohei/pugo/app/asset" // 用 pugo 的asset.go进行测试
)

func main() {
	fs := assetfs.AssetFS{
		Asset:     asset.Asset,
		AssetDir:  asset.AssetDir,
		AssetInfo: asset.AssetInfo,
	}
	http.Handle("/", http.FileServer(&fs))
	http.ListenAndServe(":12345", nil)
}

访问 http://localhost:12345,就可以看到嵌入的 source,theme,doc 的目录列表页面,和 Nginx 查看静态文件目录一样的。

go generate

嵌入静态资源的工具推荐配合 go generate 使用。例如 pugo 的入口文件就有:

package main

import (
    "os"
    "time"

    "github.com/go-xiaohei/pugo/app/command"
    "github.com/go-xiaohei/pugo/app/vars"
    "github.com/urfave/cli"
)

//go:generate go-bindata -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/...

// ......

在编译的时候执行:

go generate && go build

这个是 go generate 的基本用法。更详细的了解可以看 官方博文。

`