Go 1.16 embed

April 18, 2021 , posted under Golang Programming Youtube



in this tutorial i will show you the new go 1.16 new file embed function, i will use this to serve a static website, make sure you have Go v1.16 install. on mac i recommend you to use Homebrew.

Go module init

first, create a folder, i call it goweb(you can call it what ever you want). Inside this folder run the command go mod init github.com/jason-shen/goweb (you can change the front part to your github address).

Setup the embed assets

We need to import the newly available Go package call embed, then we need to add //go:embed assets/*, as this points embed to to our assets folder, then we do the same for the file location of the html folder like this //go:embed www/index.html.

note: the //go:embed assets/ is not a comment, its the syntaxt embed requires

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import (
	"embed"
)
//go:embed assets/*
var assets embed.FS

//go:embed www/index.html
var html []byte

Let wire all this up in the main function

Now we start coding the main function, firstly we import all the require packages you see below, then we write the fs (file system) and the http server part, then we will put this on port 8080 for testing purpose, the fmt.print is to notify the user that the program does work and who them how to exit the program.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
--- main.go
package main

import (
	"embed"
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"runtime"
)

func main()  {
	fs := http.FileServer(http.FS(assets))
	http.Handle("/assets/", fs)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-Type", "text/html")
		w.Write(html)
	})
	fmt.Println("the address is http://localhost:8080, to end press ctrl+c")
	http.ListenAndServe(":8080", nil)
}

Create the html file and the asset folder

Now we are all set on the Go side of things, next we need to create the html file and the assets folder, for this example i am just gonna create a very simple index.html, and just going to have one image in the assets folder, and use it inside the index.html.

image info
create a folder call www then create a new index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
--- index.html
<!DOCTYPE html>
<html>
  <head>Go website</head>
  <body>
    <h1>Go website</h1>
    <img src="/assets/golang.jpeg" />
    hello world
  </body>
</html>

finally just use any image as you want or you can head over to my github and grab the image i used

Extra touch

Now if you run go run main.go then head to https://localhost:8080 then you should see the webpage shows up, but we want to open the web automaticlly, how do we do that?
lets add an auto open function into our main function as below

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func openbrowser(url string) {
	var err error

	switch runtime.GOOS {
	case "linux":
		err = exec.Command("xdg-open", url).Start()
	case "windows":
		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		err = exec.Command("open", url).Start()
	default:
		err = fmt.Errorf("unsupported platform")
	}
	if err != nil {
		log.Fatal(err)
	}
}

here is the final code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
	"embed"
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"runtime"
)

//go:embed assets/*
var assets embed.FS

//go:embed www/index.html
var html []byte

func main()  {
	fs := http.FileServer(http.FS(assets))
	http.Handle("/assets/", fs)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-Type", "text/html")
		w.Write(html)
	})
	fmt.Println("the address is http://localhost:8080, to end press ctrl+c")
	openbrowser("http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

func openbrowser(url string) {
	var err error

	switch runtime.GOOS {
	case "linux":
		err = exec.Command("xdg-open", url).Start()
	case "windows":
		err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
	case "darwin":
		err = exec.Command("open", url).Start()
	default:
		err = fmt.Errorf("unsupported platform")
	}
	if err != nil {
		log.Fatal(err)
	}
}

Final step

now it all should be up and running, now we can build this project into a bin and move it to another location without the index.html and the assets fold.
without any dealt it should work, now you can distribe the single bin that has the html files embed, that makes life alot easier. until then thank you for reading.

Link to the repo

.Site.Param.name

About

I'm a FullStack developer, specialise with webrtc, voip, web and mobile apps and i love anything that is related to technology

Join the Newsletter

Subscribe to get my latest content & deal for my incoming courses.
You're signing up to receive emails from Jason Shen