Go Embedded Static resources

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

When you use Go to develop an app, you sometimes encounter situations where you need to read static resources. For example, to develop WEB applications, the program needs to load the HTML of the template file generation output. In the program deployment, in addition to publishing the application executable file, you also need to publish the dependent static resource files. This adds some trouble to the publishing process. Since publishing a single executable is a very simple operation, someone will find a way to package the static resource file into the Go program file. Here's a look at some of the solutions:

Go-bindata

Go-bindata is currently a tool for pugo embedding static resources in my program. It can embed static files in a go file and provide some ways to do it.

Installation go-bindata :

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

note the last three points ... of the go get address . This parses all subdirectories and downloads dependent compilation subdirectory content. go-bindatathe command tool is in a subdirectory. (also remember to $GOPATH/bin add the system PATH ).

Using the command tool go-bindata (pugo example):

-oOutput file to app/asset/asset.go , package name -pkg=asset , then the directory to be packaged, three points including all subdirectories. This allows all relevant files to be packaged asset.go package asset and initially maintained and directory consistent.

The code for releasing the static file in the Pugo:

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.goThe static content inside is still indexed according to the actual directory location. So we can go directly to the directory or file address to operate.

-debug Development Model

go-bindataSupport development mode, that is, do not embed static content, only generate action methods to the output go code, such as:

-debugParameters to open the development mode. The generated code directly reads the static file into memory, rather than coding it into the code. Code files are smaller and you write business logic more quickly.

// -pkg=asset, 打包的包名是 assetbytes, 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.FileSystemIs the interface that defines the HTTP static file service. go-bindatathird-party package GO-BINDATA-ASSETFS implements this interface, which supports HTTP access to the static file directory behavior. Take the example that we compiled above 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)}

Access http://localhost:12345 , you can see the embedded source , theme doc the Directory list page, and Nginx view static file directory the same.

Go.rice

Go.rice also supports packaging of static files into go files, but behaves go-bindata differently. From the perspective of use, go.rice is actually more convenient static file operation library. Wrapping a static file is a passing feature.

Install and go-bindata like, note three points :

go get github.com/GeertJohan/go.rice/...

go.riceConsider a directory to be an rice.Box operation:

import (    "fmt"    "html/template"    "github.com/GeertJohan/go.rice")func main() {    // 这里写相对于的执行文件的地址    box, err := rice.FindBox("theme/default")    if err != nil {        println(err.Error())        return    }    // 从目录 Box 读取文件    str, err := box.String("post.html")    if err != nil {        println(err.Error())        return    }    t, err := template.New("tpl").Parse(str)    fmt.Println(t, err)}

Rice command

go.riceThe packing command is rice . Very straightforward to use: in the Go Code directory with the Go.rice operation , execute directly rice embed-go :

rice embed-gorice -i "github.com/fuxiaohei/xyz" embed-go // -i 处理指定包里的 go.rice 操作

He will generate the code that embeds the file under the current package name rice-box.go . However, it does not handle import recursively. He will analyze the use of the Go code in the current directory go.rice and find the corresponding folder to embed. But the inside of the sub-directory and import the go.rice use will not be analyzed, you need to manually CD the past or -i specify the package to process the execution command. This is very unfriendly.

http. FileSystem

go.riceis the direct support http.FileSystem interface:

func main() {    // MustFindBox 出错直接 panic    http.Handle("/", http.FileServer(rice.MustFindBox("theme").HTTPBox()))    http.ListenAndServe(":12345", nil)}

A little bit cumbersome is that rice.FindBox(dir) only one directory can be loaded. So a scenario that requires multiple catalogs will have code:

func main() {    http.Handle("/img", http.FileServer(rice.MustFindBox("static/img").HTTPBox()))    http.Handle("/css", http.FileServer(rice.MustFindBox("static/css").HTTPBox()))    http.Handle("/js", http.FileServer(rice.MustFindBox("static/js").HTTPBox()))    http.ListenAndServe(":12345", nil)}

Esc

The ESC author, after studying several tools that embed static resources, finds that it's not good enough to write it himself esc . Its requirements are simple, embedded in static resources and support http.FileSystem . esctool also these two main functions.

Installation esc :

go get github.com/mjibson/esc

Use methods and go-bindata similar:

// 注意 esc 不支持 source/... 三个点表示所有子目录go-bindata -o=asset/asset.go -pkg=asset source theme doc/source doc/theme

Direct support http.FileSystem :

import (    "net/http"    "asset" // esc 生成 asset/asset.go )func main() {    fmt.Println(asset.FSString(false, "/theme/default/post.html"))         // 读取单个文件    http.ListenAndServe(":12345", http.FileServer(asset.FS(false)))     // 支持 http.FileSystem,但是没有做展示目录的支持}

escThere is a bigger problem is only one file operation, no folder operation, no similar go-bindata asset.RestoreDir() method. And there is no way to list embedded files, resulting in a file operation that cannot be done unless you write yourself dead. That's the biggest reason I don't use him.

Go generate

Tools that embed static resources are recommended for use with go generate . For example pugo , a portal file would have:

package mainimport (    "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/...// ......

Execute at compile time:

go generate && go build

This is go generate the basic usage. More detailed information can be seen in the official blog.

Summarize

I pugo tested this procedure for embedding static resources when I was developing it. go.riceIt's not the pattern I want, I don't think about it. There esc are too few operating methods available to meet the needs of program development. Last Choice go-bindata . However go-bindata go.rice , both the pure character data or the []byte character data are written to the go file, and the content is very large. escis the BASE64 encoding that is written to the gzip compression stream. The size of the go code is significantly smaller after compression (I embed text files such as templates). You can see that library classes have their own pros and cons. It would be nice to have that go-bindata rich API and esc embed compressed character data like that.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.