How to add a GUI to your Golang app in 5 easy steps (powered by Electron)

asticode
asticode
Dec 2, 2017 · 5 min read

Building a Golang app is simple and fun. But sometimes you want to add the icing on the cake: a GUI!

In this story I'll go through how to add a GUI to a simple Golang app using astilectron with its bootstrap and its bundler.

Our Golang GUI app will explore a folder and display valuable information about its content.

You can find the final code here.

Step 1: organize the project

The files will be structured as follows:

|--+ resources
|--+ app
|--+ static
|--+ css
|--+ base.css
|--+ js
|--+ index.js
|--+ lib
|--+ ... (all the css/js libs we need)
|--+ index.html
|--+ icon.icns
|--+ icon.ico
|--+ icon.png
|--+ bundler.json
|--+ main.go
|--+ message.go

As you can see, we need icons in 3 different formats to achieve cross-platform formatting: .icns for darwin, .ico for windows and .png for .linux.

We're going to use the following CSS/JS libraries:

Step 2: implement the skeleton

GO

First we need to set up astilectron’s bootstrap in main.go:

The 2 global variables AppName and BuiltAt will be automatically filled upon using the bundler (through ldflags).

As you can see our homepage will be index.html, we’ll have a nice menu with 2 items (about and close) and our main window will 700x700, centered and with a #333 background.

We also add the debug option depending on a GO flag, in case we want to use the HTML/JS/CSS dev tools.

And finally we store a pointer to the astilectron.Window in the global variable w in case we need it later using the option OnWaitthat contains a callback executed once the window, the menu and all objects have been created.

HTML

Now we need to create our HTML homepage in resources/app/index.html:

Nothing fancy here: we declare our css and js files, we set up the html structure and we make sure our own js script is initialized through index.init()

CSS

Now we need to create our CSS style in resources/app/static/css/base.css:

JS

And finally we create our own JS script in resources/app/static/js/index.js:

The init method initializes the libraries properly.

Step 3: set up the communication between GO and Javascript

Everything is starting to fall into place but we’re still missing a key component: communication between GO and Javascript.

Communicating from Javascript to GO

To communicate from Javascript to GO, we first need to send a message from Javascript to GO and execute a callback once the response has been received:

Simultaneously we need to listen to messages in GO and send back an optional message to Javascript through the MessageHandlerbootstrap option:

This simplified example would print received hello world in the Javascript output.

In our case, we’ll add some more logic since we want to allow exploring a folder and display valuable information about its content.

Therefore we add the following to resources/app/static/js/index.js :

It executes the new explore method once the Javascript astilectron namespace is ready, which then send a message to GO and, upon receiving the response, updates the HTML accordingly.

Then we add the following to message.go :

It executes the new explore method upon receiving the correct message, which returns valuable information regarding a path.

Finally, we don’t forget to add the proper MessageHandler bootstrap option as shown in the simplified example.

Communicating from GO to Javascript

To communicate from GO to Javascript, we first need to send a message from GO to Javascript and execute a callback once the response has been received:

Simultaneously we need to listen to messages in Javascript and send back an optional message to GO:

This simplified example will print received hello world in the GO output.

In our case we first add the following to main.go :

It makes the about menu item clickable and display a modal with the proper content, and it requests to display a notification 5 seconds after the GO app has been initialized.

Finally we add the following to resources/app/static/js/index.js :

It listens to GO messages and reacts accordingly.

Step 4: bundle the app

Now that the code is in place, we need to make sure we'll present our Golang GUI app the nicest way possible to our users:

  • a MacOSX app for darwin users
  • an .exe with a nice icon for windows users
  • a simple binary for linux users

Luckily for us, we have astilectron’s bundler for that!

First we install it by running:

$ go get -u github.com/asticode/go-astilectron-bundler/...

Then we add the proper bootstrap options in main.go :

Then we create the configuration file called bundler.json :

Finally we run the following command in the project directory (make sure $GOPATH/bin is in your $PATH):

$ astilectron-bundler -v

Step 5: see it in action!

And voilà! The result is in the output/<os>-<arch> folder, ready for testing :)

You can of course bundle your Golang GUI app for other environments, check out the bundler doc to see how you can achieve that.

Conclusion

With a little bit of organization and structure, adding a GUI to your Golang app has never been easier thanks to astilectron, its bootstrap and its bundler.

It’s interesting to note the 2 main downsides of using it:

  • the size of the binary will be at least 50MB, and after the first execution the size of the folder containing the binary will be at least 200MB
  • the memory consumption can be a little bit hectic since Electron (that is running under the hood) has been known to not manage it that well

But if you’re ready to go past that, you’ll add a GUI to your Golang apps in no time!

Happy GUI coding!

asticode

Written by

asticode

Freelance golang senior developer: https://asticode.com | https://github.com/asticode

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade