How to embed file for later parsing execution use

I do this with most of my Go web apps. I use go-bindata to auto-generate Go source code from all the files I want to embed and then compile them into the binary.
All this is done automatically during build.

One downside is that the current go build tools do not offer a way to hook into the build process, so I use a Makefile for this purpose. When the makefile is invoked, it runs go-bindata to generate the sources for all necessary files, then usually performs some additional code generation bits and bobs (notably, creating a Go source file which lists all the embedded files in a map.. A Table of Contents if you will). It then proceeds to compile the actual program.

This can become a little messy, but you only have to set it all up once.
Another downside, is that the use of a Makefile means the software is not compatible with the go get command. But since most of my web apps are not meant to be shared anyway, this has not been a problem so far.

When it comes to debugging/developing such an application, there is another issue that arises from embedding the static web content: I can’t just edit an HTML or CSS file and refresh the browser to see its effects. I would have to stop the server, rebuild it and restart it with every edit. This is obviously not ideal, so I split the Makefile up into a debug and release mode. The release mode does what I described above. The debug mode, however, wil not actually embed the static files. It does generate source files for each of them, but instead of having them contain the actual file data, it contains a stub which simply loads the data from the filesystem.

As far as the server code is concerned, there is no difference in the generated code. All it does is call a function to fetch the contents of a given static file. It does not care whether that content is actually embedded in the binary, or if it’s loaded from an external source. So the two build modes are freely interchangeable.

For example, the same generated function to fetch static file content in release and debug mode would look as follows:

Release mode:

func index_html() []byte {
    return []byte {
        ....
    }
}

Debug mode:

func index_html() []byte {
   data, err := ioutil.ReadFile("index.html")
   ...
   return data
}

The interface in both cases is identical. This allows for easy and care-free development and debugging.

Leave a Comment