Go (golang) + Vue.js

Go (golang) + Vue.js

With the popularity of JavaScript frameworks like Angular.js and React.js I felt the need to explore some of these libraries to see if one of them would fit into my projects. I always try to keep the complexity of my projects at a minimum, which means that the majority of these frameworks will be ignored due to the overhead and gigantic dependency trees that each of them carry.

Exploring a bit more about modern front-end development and the most popular JavaScript frameworks like Angular.js, React.js, Vue.js I went ahead and compared the development process and requirements and ended up with a lightweight approach to fire up a web application using Go for the back-end and Vue.js for the front-end without the overhead of Node.js and NPM.

/project/
├── docker-compose.yml
├── Dockerfile
├── README.md
├── backend
│   ├── app.go
│   ├── main.go
│   ├── z_foobar.go
└── frontend
    ├── public
    │   ├── app.min.js
    │   ├── bootstrap.min.css
    │   ├── favicon.ico
    │   ├── foobar.min.js
    │   ├── styles.min.css
    │   ├── vue.min.js
    │   └── vue-res.min.js
    └── views
        ├── base.html.tpl
        └── foobar.html.tpl

Back-end — main.go

The entry point for the web server is powered by a regular http.Server instance which, optionally, could benefit from a middleware like cixtor/middleware or julienschmidt/httprouter. They both offer a good easy-to-use interface with methods to handle GET, POST, PUT, etc HTTP requests.

I usually follow this example and move onto the next step.

Note: You can also consider to put the web server behind a proxy like Nginx to facilitate load balancing. However, if your project will live on one of the popular cloud services like AWS, having an extra load balancer in the middle may actually hurt the performance. AWS, for example, already provides an excellent solution: Elastic Load Balancing - ELB.

Back-end — app.go

A custom struct to hold all the resources that will be accessed by all the HTTP handlers. This includes the database instance, logger, key-value storage engine, etc all at your own discretion. I usually define generic helpers in this file as well, but it is always a matter of discussion if these helpers should be defined as functions or methods of the Application struct.

type Application {}

func NewApp() *Application {
    return new(Application)
}

Back-end — z_foobar.go

For maintainability, I put the HTTP handlers in individual files, or at least I group them by responsibility. I also use the same prefix for all of them, so I can easily separate them with a quick glance at the sidebar of my preferred code editor. Here, I use z_ as the prefix for all the HTTP handlers, which can also be considered the controllers in an MVC approach.

func (app *Application) Foobar(w http.ResponseWriter, r *http.Request) {
    if err := w.Write([]byte("Hello world from foobar\n")); err != nil {
        log.Println("page.foobar;", err)
    }
}

Front-end — vue.js + vue-res.min.js

Vue.js is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.

Lot of documentation is available on the Internet.

And more important, you don’t “require” a build tool like Babel.js, Webpack or Grunt to transform the web components into usable JavaScript code. I can understand the appeal of having such gargantuan tools in your development process, but making your web application depend on +140M of fragile JavaScript code is not what I would call smart.

You can, however, use vue-cli to have access to these tools if that’s what you want.

My only two dependencies are Vue.js and Vue-resource for HTTP requests:

Front-end — app.min.js

To offer modularity I designed a very simple application bootstrapper:

var Application = function() {};

Application.prototype.el = '#webapp';
Application.prototype.delimiters = ['${', '}'];
Application.prototype.created = function() {};
Application.prototype.methods = {};
Application.prototype.data = {};

Note: Be aware that the delimiters used to render data inside the Vue templates have to be changed because otherwise they would conflict with the delimiters used by the Go template package. Instead of using the common ⎨⎨ … ⎬⎬ we will use $⎨ … ⎬ and the rest of the features will stay the same.

Front-end — foobar.min.js

All the additional components will follow this convention:

Vue.component('foobar', {
    template: '#foobar',
    data: function() {
        return {…};
    },
    methods: {…}
});

Where foobar matches the name of the HTTP handler.

Front-end — base.html.tpl

The code should be self-explanatory.

It basically contains the initial template for all the HTML pages, the inclusion of the JavaScript files, the Go definition to load the content of other template files, and the instantiation of the Vue application. Notice how all the pages will contain an unique identifier in the <body> tag to facilitate the decoration via CSS rules.

⎨⎨define "base"⎬⎬
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Project</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" type="text/css" href="/assets/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/assets/styles.min.css">
</head>
<body id="⎨⎨.Page⎬⎬">
    <div id="webapp">
        ⎨⎨template "content" .⎬⎬
    </div>
    <script type="text/javascript" src="/assets/vue.min.js"></script>
    <script type="text/javascript" src="/assets/vue-res.min.js"></script>
    <script type="text/javascript" src="/assets/app.min.js"></script>
    <script type="text/javascript" src="/assets/⎨⎨.Page⎬⎬.min.js"></script>
    <script type="text/javascript">new Vue(new Application());</script>
</body>
</html>
⎨⎨end⎬⎬

Front-end — foobar.html.tpl

Here is an example of a web component in use defined in foobar.min.js and referenced as #foobar. Variable welcome can be defined in the object returned by the component’s data object. Everything else is normal business, you can refer to the official documentation to know what other things you can do here.

⎨⎨define "content"⎬⎬
<foobar inline-template>
    <p>⎨⎨welcome⎬⎬</p>
</foobar>
⎨⎨end⎬⎬

Conclusion

From here you can continue the development with your own decisions. The advantage of this approach is that you don’t need to recompile the Vuex templates because they are defined as regular HTML code and rendered at runtime by the Go template package. A restart of the web server will only be necessary if you need to include more data or extend the current functionality.

But wait… what about vue-cli?

Vue-cli is a tool for rapid Vue.js development. You are, of course, free to use it but be aware that as of today (May, 2018) a bare bone project created via vue-cli with only Eslint and Prettier weights +134M. I don’t want to know how much the project will weight if I decide to all one or more of the other suggested dependencies like Router, Vuex, Babel, etc.

Do you have a project idea? Let's make it together!