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.
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
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.ricewhich makes working with resources such as html, JS, CSS, images, templates very easy.
go get github.com/GeertJohan/go.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.
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.
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.
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.
The first step is we spin up a node container that has access to
yarn, copy over our react code including our
yarn.lockfile so that we persist package versions, we run a
yarnto pull all our packages and finally run a
yarn buildto build a static version of the site
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
cmd/golang-reactfolder and run our
GOOS=linux GOARCH=amd64 go build -o golang-react.linux.x86_64 .to create a linux binary.
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.
docker-compose up --build to build and spin up our new container. You should see the following in your terminal.
You can now visit
http://localhost:1323 and you should see your new react application.