Bundle HTML, CSS, And JavaScript To Be Served In A Golang Application

So I’ve been working on a project that uses the Go programming language. The application I’m building is a web application that I plan to distribute. The thing is, I don’t want to distribute hundreds of files to make it possible. The application has an API built with Go and the front-end that consumes the API is built with Angular. This lead me searching for a way to bundle all the files into the final binary.

There are several packages that exist for bundling assets into a Golang application. Popular packages include go-bindata, go-bindata-assetfs, and go.rice. I had the most success with go.rice, so we’re going to explore it in this article.

Now I’m building a Go with Angular application, but I think that will yield too complex of an example for this article. Instead we’re going to build a very simple application that uses Golang, HTML, CSS, and JavaScript.

Create a Project and Download the Dependencies

Before going any further, the assumption is that you have Go installed and the proper paths configured. With that said, create a myproject somewhere on your computer.

This project should contain the following files and directories:

touch main.go
mkdir website
touch website/index.html
touch website/custom.css
touch website/app.js

If you don’t have the mkdir and touch commands, just create the files manually. There are a few packages that must be installed now. Execute the following:

go get github.com/GeertJohan/go.rice
go get github.com/GeertJohan/go.rice/rice
go get github.com/gorilla/mux

The mux library will make it easier for us to work with routes, but if you really wanted to, you could just use the default Golang libraries. If you want to learn more about creating an API with the mux library, you can check out my previous tutorial on the subject.

At this point in time we can develop the application.

Develop the Application for Serving Assets

We’re going to start by developing the website portion of the application before the Golang portion. Just to demonstrate bundling all kinds of files, we’re going to work with HTML, JavaScript, and CSS.

Let’s start with the styles. Open the project’s website/custom.css file and include the following:

.container {
    width: 400px;
    height: 100px;
    background-color: #009ACD;
    margin: auto;
}

.text {
    position: relative;
    top: 50%;
    transform: translateY(-50%);
    text-align: center;
    color: #FFFFFF;
}

Essentially we just want a colored container with vertical aligned text in it. Now let’s take a look at the small bit of application JavaScript.

Open the project’s website/app.js file and include the following JavaScript code:

document.getElementById("text").innerHTML = "Hello World<br /><p>Created by Nic Raboy</p>";

The above line will look for a UI component with an id of text and fill it with HTML.

Now let’s bring it together with our very simple HTML markup. Open the project’s website/index.html file and include the following markup:

<html>
    <head>
        <title>The Polyglot Developer</title>
        <link rel="stylesheet" href="custom.css" />
    </head>
    <body>
        <div class="container">
            <p id="text" class="text"></p>
        </div>
        <script src="app.js"></script>
    </body>
</html>

Again, nothing very complicated as of now. We’re just demonstrating a website with several file components to it. A perfect candidate for bundling into a Golang application.

Now let’s check out our Go code. We won’t have any API endpoints in this application, but we could if we wanted to. Open the project’s main.go file and include the following code:

package main

import (
    "log"
    "net/http"

    "github.com/GeertJohan/go.rice"
    "github.com/gorilla/mux"
)

func main() {
    router := mux.NewRouter()
    router.PathPrefix("/").Handler(http.FileServer(rice.MustFindBox("website").HTTPBox()))
    log.Fatal(http.ListenAndServe(":12345", router))
}

The most important line in this file is the one where we use the go.rice component. What we are doing is we are saying that we want our assets found in website to be served and accessible from the root path of our served application. This means that when we serve our application, we can access it from http://localhost:12345/.

We’re not quite done. We know where our files are, but the application will not be truly reading from those files. Instead we need to bundle these assets into a Go file that can be compiled into our application.

Bundle the Assets that will be Served

The way the go.rice package works is it looks at our source code for the MustFindBox function. It finds the website directory and understands that we need to bundle that directory.

To bundle the assets we need to use a separate application, not the standard go build that we’ll do soon. We’ve already downloaded the separate application. If it isn’t already in your path, add the following:

export PATH=$PATH:$GOPATH/bin

Depending on your operating system, the above command could be different. This will allow us to do the following:

rice embed-go

The above command will create a file called rice-box.go in your project. Open it and see what it contains. You’ll notice that it contains the data to each of your website files.

When you build your Go application, the website data will be built in. That means you only need to pass around one executable application.

Conclusion

You just saw how to bundle web assets into a Golang application. There are plenty of reasons why this would be useful. One example is that you’d like to distribute one application file that has a web interface built in. This is perfect for building cross platform applications that have a UI rather than just a CLI.

Want more information on building an API for this bundled application? Check out this full stack tutorial I wrote on the subject.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

Search

Follow Us

Subscribe

Subscribe to my newsletter for monthly tips and tricks on subjects such as mobile, web, and game development.

Subscribe on YouTube

Support This Site