A simple go package that embeds static files in Go Binaries for packaging and easy release of software
There are two ways you can go about this:
- You can install from the command line by running
$ go get github.com/oluwadamilareolusakin/embedfiles - You can add a go generate directive to your go binary after your last import statement
//go:generate go get github.com/oluwadamilareolusakin/embedfiles. We will talk about how to run this in a second.
Add a go generate directive to your go binary `//go:generate embedfiles "see_first_arg_description_below" "path_to_static_files" "see_third_arg_description_below"
The first argument to your command is the path where you want your newly generated package to live and be accessed from. Say I had a module called blog, which I want to embed files for. My folder structure may look something like:
blog # Top-level module name
├── ...
├── templates
│ ├── index.html # shows all blog posts
│ ├── new.html # Renders form to create new blog post
│ └── ...
├── server # Handles browser requests
│ ├── server.go
│ ├── server_test.go
├── pageio # Handles storing and retrieving blog pages
│ ├── pageio.go
├── ...
In this case, I may decide to add a subdirectory to /blog/ named statictemplates as my new package name. Then my first argument may look like ../statictemplates/template.go. My file structure then becomes:
blog # Top-level module name
├── ...
├── templates
│ ├── index.html # shows all blog posts
│ ├── new.html # Renders form to create new blog post
│ └── ...
├── server # Handles browser requests
│ ├── server.go
│ ├── server_test.go
├── pageio # Handles storing and retrieving blog pages
│ ├── pageio.go
├── statictemplates # Directory and package file created after I run `go generate`
│ ├── template.go
├── ...
##### Third arg description
The third argument is the name of the package we mentioned above, in our case "statictemplates". This will ensure that our `tempate.go` file looks something like:
package statictemplates
....
......
Putting it together, my go generate directives may look like in server.go:
//go:generate go get "github.com/oluwadamilareolusakin/embedfiles"
//go:generate embedfiles "../statictemplates/template.go" "../templates" "statictemplates"
After you have completed all the steps above, you may run your generate command. In the root of your module, in our case /blog/ you may run $ go generate ./...
This command will search for all go generate directives in the directory and run them. To confirm this worked, you can checkout /blog/statictemplates/template.go and you should see something like:
package statictemplates
// Code generated by go generate, DO NOT EDIT
func init() {
vault.Add("/404.html", []byte{60, 104, 49, 62, 87, 104, 111, 111...})
...
}
type Vault struct {
storageUnit map[string][]byte
}
func newVault() *Vault {
return &Vault{storageUnit: make(map[string][]byte)}
}
func (vault *Vault) Add(filename string, content []byte) {
vault.storageUnit[filename] = content
}
func (vault *Vault) GetFile(filename string) []byte {
return vault.storageUnit[filename]
}
var vault = newVault()
func Add(filename string, content []byte) {
vault.Add(filename, content)
}
func Get(filename string) []byte {
return vault.GetFile(filename)
}
You can now use all the embedded files and the methods from the statictemplates package throughout your program. Et Voila! You have generated a go binary that has your static files embedded as bytes 🎉
To use these files in your program, follow these steps:
For example, if we want to use the files in server.go we may add the package import:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"regexp"
"github.com/oluwadamilareolusakin/gowiki/pageio"
"github.com/oluwadamilareolusakin/gowiki/statictemplates" // import added
)
An example could be rendering a template for the 404.html template we embedded:
func renderTemplate(w http.ResponseWriter, title string, page *pageio.Page) {
templateKey := "/" + title + ".html" // something like "/404.html"
data := string(statictemplates.Get(templateKey)) // using the .Get method from statictemplates
templ := template.Must(template.New("").Parse(data))
err := templ.Execute(w, page)
handleError(w, err)
}
There you have it, you can now ship your apps without worrying about copying over static files and publishing them! Happy Tinkering! 🚀
If you have some feedback or suggestions, I'd love to hear them, you can shoot me a mail projects@oluwadamilareolusakin.com or find me on Twitter