Go resource bundling
embed.FS
With the release of Go 1.16 in February 2021, a new feature, embed.FS
, was introduced, providing a native way to embed static files into Go binaries. This feature eventually led to the deprecation of pkger
(if you are using Go pre-1.16, see pkger).
embed.FS
simplifies the process of embedding files directly into your Go applications without external dependencies. Unlike pkger
, which uses reflection at compile time, embed.FS
is more straightforward and integrates seamlessly with the Go toolchain.
Usage of embed.FS
Using embed.FS
is simple. First, you need to import the embed
package:
import "embed"
Then, you can use the //go:embed
directive to specify the files or directories to embed:
//go:embed templates/page.tmpl
var tmplFS embed.FS
Example
To bundle the same Go template file as in the pkger
example, you can use embed.FS
like this:
import (
"embed"
"text/template"
"io/fs"
"os"
)
//go:embed templates/page.tmpl
var tmplFS embed.FS
func main() {
tmplData, _ := fs.ReadFile(tmplFS, "templates/page.tmpl")
tpl, err := template.New("page").Parse(string(tmplData))
if err != nil {
panic(err)
}
_ = tpl.Execute(os.Stdout, ...)
}
Building Your Application
With embed.FS
, there’s no need for a separate bundling step. You simply build your application as usual:
go build
The introduction of embed.FS
in Go 1.16 provides a more native and efficient way of embedding files in Go applications. While pkger
served well for a time, embed.FS
is now the recommended approach for most use cases.
This structure should integrate well with your existing blog post, providing a clear and concise comparison between pkger
and embed.FS
, and guiding readers on how to transition to the newer method.
pkger
Notes on the installation and usage of pkger.
Installation done with
go get github.com/markbates/pkger/cmd/pkger
pkger
works by bundling the resources with a code-generated pkg.go
.
The configuration of assets to be bundled is done by reflection at compile time and not direct configuration.
This is done by replacing standard Go file operations with pkger
proxy ones, such as:
type Pkger interface {
Parse(p string) (Path, error)
Current() (here.Info, error)
Info(p string) (here.Info, error)
Create(name string) (File, error)
MkdirAll(p string, perm os.FileMode) error
Open(name string) (File, error)
Stat(name string) (os.FileInfo, error)
Walk(p string, wf filepath.WalkFunc) error
Remove(name string) error
RemoveAll(path string) error
}
type File interface {
Close() error
Info() here.Info
Name() string
Open(name string) (http.File, error)
Path() Path
Read(p []byte) (int, error)
Readdir(count int) ([]os.FileInfo, error)
Seek(offset int64, whence int) (int64, error)
Stat() (os.FileInfo, error)
Write(b []byte) (int, error)
}
Example
Bundling a Go template file.
tmplFile, _ := pkger.Open("/templates/page.tmpl")
tmplBytes, _ := ioutil.ReadAll(tmplFile)
tmplString := string(tmplBytes)
tpl, err := template.New("page").Parse(tmplString)
_ = tpl.Execute(f, ...)
The bundling is simply done by running
pkger
and building as usual
go build