DEV Community

Cover image for Serving Static Sites with Go
Esslam Ben Ramadan
Esslam Ben Ramadan

Posted on

Serving Static Sites with Go

During a team meeting this week, I was given the task to see if we could bundle and serve our static react code inside of a Go server and produce a single binary that would be placed inside a docker container and can be run at any point to serve our site.

  • Link to the Github repository if you just want to have a look at structure.

Prerequisite

  • Go
  • Docker

Folder Structure

Alt Text

What you want to do first is create an empty folder with your project name in your go path. For the purpose of keeping this guide simple I will keep all the code very basic and only have two top level folders as the point of the article is to explain how to link these individual tools.

My two top level folders will be cmd which will contain all my go code and will be the main entry point for the application. The second will be web which will contain my JavaScript code.

The Go Side

Let’s start by going inside of our cmd folder and creating a new folder with our project name, mine will be called golang-react.

Inside of this folder you want to create a main.go file which will be the entry point for our server and will be the code that we use to create the binary.
Before copying the below code you will want to install two go packages

  • echo which is a high performance, minimalist Go web framework which you can install by running.go get -u. github.com/labstack/echo/...

  • go.rice which makes working with resources such as html, JS, CSS, images, templates very easy. go get github.com/GeertJohan/go.rice github.com/GeertJohan/go.rice/rice

The basic idea here is that we are using the rice box package to find our react build folder and generates a single Go source file called rice-box.go. The generated go file contains all assets. The Go tool compiles this into the binary and allows us to serve our web application as a single binary.

The React Side

I think a better name for this section could be The JavaScript Side as it really doesn’t matter what framework/no framework setup you have as long as you are able to produce a static bundle. However due to the current eco system and the fact that I use react at work I will create our bundle using create react app.

What you want to do first is cd into the web folder within our application and create a new folder and name it whatever your react app is called. You can then run npx create-react-app to create a react application within the current folder which will create a boiler plate react application for us.

How to run it

At this point we have everything we need to get started and we can actually create a go binary with our assets bundled and run it. We should still be in our web/projectname folder in our terminal so you can just run yarn build which will produce a static bundle for us.

You should now navigate to your cmd/projectname in our terminal and run our go.rice build command rice embed-go which will find our asset references and compile them so that they can be bundled alongside our final binary. This will create a rice-box.go file in the same folder.

For the final step we just want to run go build . to create a binary in our current location. It should create a binary with your project name which you can run by typing ./projectname in your terminal which should serve our application.

The Docker Side (Optional)

This part is optional as we’ve already created our binary. What this step will let you do is create the binary and run it as a docker container.

The basics of the code below is we split our our image build process in three steps.

  1. The first step is we spin up a node container that has access to npm and yarn, copy over our react code including our package.json and yarn.lock file so that we persist package versions, we run a yarn to pull all our packages and finally run a yarn build to build a static version of the site

  2. The second step spins up a go server and copies all our local code to the equivalent path on our go server. It then copies our frontend build folder in to the /web/frontend/ folder ready for us to compile it. We then change our WORKDIR to our cmd/golang-react folder and run our rice embed-go and GOOS=linux GOARCH=amd64 go build -o golang-react.linux.x86_64 . to create a linux binary.

  3. The final step creates a very simple alpine server. We copy our binary to the new container and set the entry path.

Only thing left to do is set up our docker-compose.yml and expose the port to our local port equivalent so we can view the website.

Run docker-compose up --build to build and spin up our new container. You should see the following in your terminal.

Alt Text

You can now visit http://localhost:1323 and you should see your new react application.

Discussion (0)