Single-binary Web Apps in Go and Vue — Part 3
By: Adam Presley
Tags: Golang, JavaScript, Vuejs, Software Development, Development

Photo by Annie Spratt on Unsplash

This is part 3 in a four part series where we will demonstrate building a web application using Go and Vue, and finally bundle it all together in a single binary for super-easy deployment/distribution. Part 1 can be found here and part 2 here.

In part 1 we built the Go and Vue apps. In part 2 we changed the Go app to automatically start the Vue app by running Node when the version of the application is “development”. In this article we are going to do the following.

Build a final version of the Vue app Bundle the final Vue app into our Go app Ensure the Go app doesn’t start Node when the version variable is something other than “development”

Building the Vue App

The Vue CLI tool provides a way to build your application into an HTML page and optimized JavaScript. To do this simply open a terminal and execute the following.

$ cd example/app

$ npm run build

Once Vue finishes compiling you should have a new subdirectory named dist which contains your compiled assets.

Bundling JavaScript Into Go

Now that we have the final JavaScript build we want to bundle it into our Go application. To do this we will be using a Go package named vfsgen.

The first step is to create a directory where our compiled assets will live. We will also create a Go file which will tell vfsgen where to find assets to bundle.

$ cd example

$ mkdir assets

$ cd assets

$ touch ./AssetConfiguration.go

In the code above we made a new directory called assets, and we’ve made a new Go file named AssetConfiguration.go. Let’s add some code there.

The purpose of AssetConfiguration.go is to tell vfsgen where to find files to bundle. Note that we have defined file types to skip over. These are files that we don’t want bundled. Also note on line 27 the directory path ./app/dist/ . This is where our compiled JavaScript lives.

The other notable thing is line 1. Here we are defining a build tag for this file. We are specifying that this file is only to be included in the build when the application is compiled with a build tag of dev. More on this in a minute.

The next step is to create a Go file that actually executes the bundling, and saves it to a Go file to be included in the final compile.

$ cd example

$ touch ./assets_generate.go

Here we’ve created the Go file that executes the bundling. Let’s add some code to it.

Let’s break down what we have here.

Line 1 tells the Go compile to only include this file if the build tag is ignore. This is because we don’t ever want to include this in our application. We ONLY use it to build the bundled assets

Lines 15–20 are the good stuff. This tells vfsgen to bundle our assets as defined in the “assets” package. We did that in the file /assets/AssetConfiguration.go. The final asset bundle will be generated into a file at ./assets/appcode.go, with a package of “assets”.

OK, one more step. To make life a little easier let’s setup our project to generate the compiled asset bundle when we run go generate . To do this we need to add the following to the top of our main.go file.

//go:generate go run -tags=dev assets_generate.go

When you run go generate in the terminal the above will tell Go to run the assets_generate.go script to generate the assets file. Go ahead and try it. You should get a new Go file in the assets subdirectory.

Serving Bundled JavaScript

Now that we have bundled the Vue application into Go code we need to be able to serve it up when the user visits http://localhost:8080 . To do that we need to add two lines of code to main.go.

The first line to add is to include the assets bundle package (change the package path to match your own).

import "gitHub.com/adampresley/example/assets"

The next thing to do is register an HTTP handler to serve our bundled static assets. Let’s add a line to do that.

httpServer.GET("/*", echo.WrapHandler(http.FileServer(assets.Assets)))

The above line of code tells our HTTP server to serve up our bundled assets at the root URL. This way when you browse to your application site it will automatically serve index.html and all the JavaScript associated with it. Let’s see the new, full listing of main.go with all of our modifications.

Testing It

Finally! Let’s make a final bundle and build. Then we can run the compiled application and see that everything is in a single binary!

$ cd app

$ npm run build

$ cd ..

$ go generate

$ go build -tags=prod -ldflags="-X 'main.Version=1.0.0'"

Or if you prefer a one liner…

cd app && npm run build && cd .. && go generate && go build -tags=prod -ldflags="-X 'main.Version=1.0.0'"

When you run the application you should see output similar to the screenshot above. Now open a browser and navigate to http://localhost:8080 .

Voila! And see the version at the bottom? That is because of the -ldflags argument we passed to Go build. That argument altered the variable Version in main.go.

And there you have it! A single binary with all of your Vue static assets bundled in! Stay tuned for part 4 where we use make to simplify building and assigning a version number. Happy coding!