How to add a GUI to your Golang app in 5 easy steps (powered by Electron)
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 OnWait
that 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 MessageHandler
bootstrap 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 forwindows
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!