vfsgen
Package vfsgen takes an http.FileSystem (likely at go generate
time) and
generates Go code that statically implements the provided http.FileSystem.
Features:
-
Efficient generated code without unneccessary overhead.
-
Uses gzip compression internally (selectively, only for files that compress well).
-
Enables direct access to internal gzip compressed bytes via an optional interface.
-
Outputs gofmt
ed Go code.
Installation
go get -u github.com/cwen0/vfsgen
Usage
Package vfsgen
is a Go code generator library. It has a Generate
function that takes an input filesystem (as a http.FileSystem
type), and generates a Go code file that statically implements the contents of the input filesystem.
For example, we can use http.Dir
as a http.FileSystem
implementation that uses the contents of the /path/to/assets
directory:
var fs http.FileSystem = http.Dir("/path/to/assets")
Now, when you execute the following code:
err := vfsgen.Generate(fs, vfsgen.Options{})
if err != nil {
log.Fatalln(err)
}
An assets_vfsdata.go file will be generated in the current directory:
package main
import ...
var assets http.FileSystem = ...
Then, in your program, you can use assets
as any other http.FileSystem
, for example:
file, err := assets.Open("/some/file.txt")
if err != nil {
return err
}
defer file.Close()
http.Handle("/assets/", http.FileServer(assets))
vfsgen
can be more useful when combined with build tags and go generate directives. This is described below.
go generate
Usage
vfsgen is great to use with go generate directives. The code invoking vfsgen.Generate
can go in an assets_generate.go file, which can then be invoked via "//go:generate go run assets_generate.go". The input virtual filesystem can read directly from disk, or it can be more involved.
By using build tags, you can create a development mode where assets are loaded directly from disk via http.Dir
, but then statically implemented for final releases.
For example, suppose your source filesystem is defined in a package with import path "example.com/project/data" as:
package data
import "net/http"
var Assets http.FileSystem = http.Dir("assets")
When built with the "dev" build tag, accessing data.Assets
will read from disk directly via http.Dir
.
A generate helper file assets_generate.go can be invoked via "//go:generate go run -tags=dev assets_generate.go" directive:
package main
import (
"log"
"example.com/project/data"
"github.com/cwen0/vfsgen"
)
func main() {
err := vfsgen.Generate(data.Assets, vfsgen.Options{
PackageName: "data",
BuildTags: "!dev",
VariableName: "Assets",
})
if err != nil {
log.Fatalln(err)
}
}
Note that "dev" build tag is used to access the source filesystem, and the output file will contain "!dev" build tag. That way, the statically implemented version will be used during normal builds and go get
, when custom builds tags are not specified.
vfsgendev
Usage
vfsgendev
is a binary that can be used to replace the need for the assets_generate.go file.
Make sure it's installed and available in your PATH.
go get -u github.com/cwen0/vfsgen/cmd/vfsgendev
Then the "//go:generate go run -tags=dev assets_generate.go" directive can be replaced with:
//go:generate vfsgendev -source="example.com/project/data".Assets
vfsgendev accesses the source variable using "dev" build tag, and generates an output file with "!dev" build tag.
Additional Embedded Information
All compressed files implement httpgzip.GzipByter
interface for efficient direct access to the internal compressed bytes:
type GzipByter interface {
GzipBytes() []byte
}
Files that have been determined to not be worth gzip compressing (their compressed size is larger than original) implement httpgzip.NotWorthGzipCompressing
interface:
type NotWorthGzipCompressing interface {
NotWorthGzipCompressing()
}
Comparison
vfsgen aims to be conceptually simple to use. The http.FileSystem
abstraction is central to vfsgen. It's used as both input for code generation, and as output in the generated code.
That enables great flexibility through orthogonality, since helpers and wrappers can operate on http.FileSystem
without knowing about vfsgen. If you want, you can perform pre-processing, minifying assets, merging folders, filtering out files and otherwise modifying input via generic http.FileSystem
middleware.
It avoids unneccessary overhead by merging what was previously done with two distinct packages into a single package.
It strives to be the best in its class in terms of code quality and efficiency of generated code. However, if your use goals are different, there are other similar packages that may fit your needs better.
Alternatives
go-bindata
- Reads from disk, generates Go code that provides access to data via a custom API.go-bindata-assetfs
- Takes output of go-bindata and provides a wrapper that implements http.FileSystem
interface (the same as what vfsgen outputs directly).becky
- Embeds assets as string literals in Go source.statik
- Embeds a directory of static files to be accessed via http.FileSystem
interface (sounds very similar to vfsgen); implementation sourced from camlistore.go.rice
- Makes working with resources such as HTML, JS, CSS, images and templates very easy.esc
- Embeds files into Go programs and provides http.FileSystem
interfaces to them.staticfiles
- Allows you to embed a directory of files into your Go binary.togo
- Generates a Go source file with a []byte
var containing the given file's contents.fileb0x
- Simple customizable tool to embed files in Go.embedfiles
- Simple tool for embedding files in Go code as a map.packr
- Simple solution for bundling static assets inside of Go binaries.rsrc
- Tool for embedding .ico & manifest resources in Go programs for Windows.
Attribution
This package was originally based on the excellent work by @jteeuwen on go-bindata
and @elazarl on go-bindata-assetfs
.
License