Navigate back to the homepage

Go Embed instead of Packr

Sudaraka Jayathilaka
December 6th, 2021 · 2 min read

Many of the microservices I am working right now, are written in Golang. Most of these microservices have internal dashboards and the UI tend to be served from the respective microservices. For serving a UI from a golang service (or any other service), you need to serve the UI files from the service. But specially in Golang, this used to be not very straight forward. Althogh we can serve files from a certain folder using a static file server feature in Golang, the language was missing the native support to bundle ui files with the service executable. For getting this done, there are several open source golang libraries out there such as,

We we using the packer library from above. On the high level, these libraries serialized all the static content and stored the serialized contents inside .go files. So once we update any of the static contents, we had to run a specific command for the serialization and generating the new .go files.

But then on one bright sunny day, Golang team introduced their latest feature, Embedded Files in their latest version go 1.16. Since this native way of embedding files eliminates the need of generating files explicitly and it looks more convenient, we wanted to make the switch in our services.

I faced with few challenges while doing the switch,

  1. Go embed directive doesn’t support paths with .. according to the documentation (accessing the parent file)
  2. Go embed always considers the path from the root. eg: if the file is project-root/static/index.html you will be able to access the file on http://localhost:8080/static/index.html

As the solution to the first problem, I ended up defining the //go:embed directive in the main.go

But as a solution to the other problem, I came up with the following implementation,

main.go

1package main
2
3import (
4 "embed"
5 "log"
6 "net/http"
7)
8
9//go:embed static/*
10var staticContent embed.FS
11
12func main() {
13 http.Handle("/", http.FileServer(http.FS(StaticFS{staticContent})))
14 log.Fatal(http.ListenAndServe(":8080", nil))
15}
16

staticfs.go

1package main
2
3import (
4 "embed"
5 "io/fs"
6 "path"
7)
8
9type StaticFS struct {
10 content embed.FS
11}
12
13func (c StaticFS) Open(name string) (fs.File, error) {
14 return c.content.Open(path.Join("static", name))
15}
16

You can see a working demo in below repo

More articles from Sudaraka Jayathilaka

Kafka Rebalancing, Kafka lag and Deployments

I have been working with Kafka for a while now. I wanted to blog about some of the common failure patterns I have seen in associated with…

October 13th, 2024 · 3 min read

Coding a neural network from scratch

Learning how AI works on a deeper level has always been in my bucket list. I found this amazing video by Andrej Karpathy which walks you…

June 6th, 2024 · 2 min read
© 2021–2024 Sudaraka Jayathilaka
Link to $mailto:sudarakayasindu@gmail.comLink to $https://github.com/sudaraka94Link to $https://www.linkedin.com/in/sudarakajayathilaka/Link to $https://x.com/sudaraka94Link to $https://medium.com/@sudarakayasindu