Go embed: Embed your HTML frontend in Golang
How to embed HTML files in Go (build and run in multiple locations)
Table of contents
No headings in the article.
Parsing HTML files into Go can be easy using the "html/template" package until the main file is moved somewhere else or errors arise because you did not use containers (or docker) when hosting the application. In Go 1.16, a package called embed
was introduced and it serves many purposes but mainly: embedding "anything" - strings, bytes, even files. This article explains how to use the embed package to insert HTML files into your golang application, build the golang app into an executable(.exe) file, and run that .exe file anywhere on your system without "HTML file not found" errors popping up.
Pre-requisites:
- Golang installed on your system
- basic knowledge of Golang
The finished project can be found here: finished project
Setup the project: - create a folder in your $GOPATH and name it go-embed
- cd into go-embed and run: go mod init go-embed`
- create the
main.go
inside the go-embed folder - create a folder
templates
, cd intotemplates
and create theindex.html
file
Updating the files:
For the index.html, we display a simple message.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go Embed</title>
</head>
<body>
<h4>Go Embed: Embed HTML in Go</h4>
</body>
</html>
For the main.go file, we serve the HTML. I am using the default "net/http" package but you can use any package of your choice e.g. the "gorilla/mux" package.
main.go
:
package main
import (
"fmt"
"html/template"
"log"
"net/http"
)
func indexHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("templates/index.html") // serving the index.html file
if err != nil {
log.Fatal(err)
}
tmpl.Execute(w, nil)
}
func main() {
http.HandleFunc("/", indexHandler)
fmt.Println("Server starting on port 8000!")
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal(err)
}
}
Run the application: go run main.go
Open our app on the browser:
Using the embed package:
In this section, we would embed the HTML file(index.html) in the Go binary which allows us to send the binary file anywhere and run that file without displaying any error.
Updating main.go
:
package main
import (
"embed"
"fmt"
"html/template"
"log"
"net/http"
)
//go:embed templates
var tplFolder embed.FS // embeds the templates folder into variable tplFolder
func indexHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFS(tplFolder, "templates/index.html")
if err != nil {
log.Fatal(err)
}
println("Embedded the index.html file")
tmpl.Execute(w, nil)
}
func main() {
http.HandleFunc("/", indexHandler)
fmt.Println("Server starting on port 8000!")
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal(err)
}
}
Run the application: go run main.go
Refresh the browser page:
Check the running application server:
We do not have any error, instead we have successfully embedded index.html.
Building the file:
First we stop the app server running.
Build the file by running: go build
We have a binary application:
Move the binary file somewhere else and run it: ./go-embed
for Linux/Mac or go-embed
for Windows.
Refresh the browser page:
Our app server:
Where can this embed feature be applied?
An example: Github
Here, I embedded all the HTML files which allow me to perform the authentication (registration or login) anywhere my application is even though the HTML files are not present. This makes hosting the application on Heroku or any hosting platform easier without getting file errors.