Go is known to create statically linked binaries without any runtime dependencies. Static binaries are great for deployment as it needs just one file resulting in less chances of envionment specific issues.
But there is one issue, If you want to embed some static assets(Front-end files, Images etc) There was no native way to do so.
This changes with Go 1.16, Go introduces new embed
package to solve this issue.
How to use embed #
There are 3 ways to use embed package.
- Get file as string
- Get file as byte slice
- Get file(s) as
embed.FS
type
Even though embed
package is not referenced in first 2 ways, it need to be imported. It can be imported as import _ "embed"
Get file as string #
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s string
func main() {
fmt.Println(s)
}
Get file as []byte #
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var b []byte
func main() {
fmt.Println(string(b))
}
Get file as embed.FS #
package main
import (
"embed"
"fmt"
)
//go:embed hello.txt
var f embed.FS
func main() {
data, _ := f.ReadFile("hello.txt")
print(string(data))
}
How to serve front end application using Go embed #
Lets see how we can serve any front end build directory using embed
.
Change the filename to a filepath in go:embed
comment. Like below
//go:embed client/build
var content embed.FS // build directory holds a client react build
Go 1.16 has also introduced few more changes like http.FS
and one more package io/fs
to make it easier to work with filesystem.
To convert embed.FS
to http.FileSystem
, http.FS
can be used, So we can do
http.Handle("/", http.FileServer(http.FS(content)))
But there is an issue, Now we need to access HOST/client/build
to access index.html
file. We need to serve subdirectory of content, which we can get using
fsys := fs.FS(content)
contentStatic, _ := fs.Sub(fsys, "client/build")
Final Code
package main
import (
"embed"
"io/fs"
"net/http"
)
//go:embed client/build
var content embed.FS
func clientHandler() http.Handler {
fsys := fs.FS(content)
contentStatic, _ := fs.Sub(fsys, "client/build")
return http.FileServer(http.FS(contentStatic))
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", clientHandler())
http.ListenAndServe(":3000", mux)
}
Full code link : https://github.com/akmittal/go-embed
Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated ! For feedback, please ping me on Twitter.
Published