现在的很多程序都会提供一个 Dashboard 类似的页面用于查看程序状态并进行一些管理的功能,通常都不会很复杂,但是其中用到的图片和网页的一些静态资源,如果需要用户额外存放在一个目录,也不是很方便,如果能打包进程序发布的二进制文件中,用户下载以后可以直接使用,就方便很多。
最近在阅读 InfluxDB 的源码,发现里面提供了一个 admin 管理的页面,可以通过浏览器来执行一些命令以及查看程序运行的信息。但是我运行的时候只运行了一个 influxd 的二进制文件,并没有看到 css, html 等文件。
原来 InfluxDB 中使用了 statik 这个工具将静态资源都编译进了二进制文件中,这样用户只需要运行这个程序即可,而不需要管静态资源文件存放的位置。
go get -d github.com/rakyll/statik
go install github.com/rakyll/statik
首先要声明,一般在 main.go 文件中,这样直观一些:
package main
//go:generate statik -src=../../web/public -dest=../../internal -f
func main() {
}
这段声明的意思是,使用 statik 命令将目录../../web/public
下的文件和目录编译到一个go文件中,此文件为../../internal/statik/statik.go
,会自动创建之。
go:generate
指令需要手动执行,来到根目录下go generate ./…
statik.go
文件内容为
// Code generated by statik. DO NOT EDIT.
package statik
import (
"github.com/rakyll/statik/fs"
)
func init() {
data := ".............."
fs.Register(data)
}
将文件信息注册到 fs 之后,就可以实例化出来一个 http.FileSystem 对象
var statikFS http.FileSystem
statikFS, err = fs.New()
然后就可以指定文件名来读取文件内容了
file, err := statikFS.Open("/index.html")
这里返回的 file 类型是http.File
,它服务于文件系统 FileSystem ,因此它是只读的,没有提供写的接口。
// A File is returned by a FileSystem's Open method and can be
// served by the FileServer implementation.
//
// The methods should behave the same as those on an *os.File.
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]fs.FileInfo, error)
Stat() (fs.FileInfo, error)
}
在vue项目中,我们只需要返回 index.html
的内容即可,具体实现如下
m.Get("/", func(ctx *macaron.Context) {
file, err := statikFS.Open("/index.html")
if err != nil {
logger.Error("读取首页文件失败: %s", err)
ctx.WriteHeader(http.StatusInternalServerError)
return
}
io.Copy(ctx.Resp, file)
})
当然 public 目录中的应该是打包好的 vue 项目。