Go and WebUI

Stefan Alfbo - Jun 7 - - Dev Community

Last week Microsoft released this blog post, An even faster Microsoft Edge, where they introduced WebUI 2.0. This has been an internal project in the Edge project, which can be summarized as a new markup-first architecture that should reduce code size and JavaScript use, giving more performance and responsiveness.

Or simply,

Use any web browser as GUI. With your preferred language in the backend.

The WebUI library is written in pure C and can be used by many different programming languages, where Go is one option.

Here is a test drive of the new library from Microsoft by using the Go language. We start out with creating the building blocks for the project.



mkdir go-webui && cd $_

go mod init go.webui
go get github.com/webui-dev/go-webui/v2/@v2.4.0

touch main.go
code .


Enter fullscreen mode Exit fullscreen mode

The most interesting line here is the one where we add the go-webui dependency to the project. With this boilerplate stuff in place we can move on to the actual code.

The program we will be writing is basic and look like this.

the program

If you push the Ok button it will create a timestamp in a file. The code below is the complete program and should added to main.go.



package main

import (
    "fmt"
    "os"
    "time"

    "github.com/webui-dev/go-webui/v2"
)

func main() {
    window := webui.NewWindow()

    webui.Bind(window, "OkButton", onOkButtonClicked)

    webui.Show(window, `
    <!doctype html>
    <html>
        <head>
            <meta charset="UTF-8" />
            <title>WebUI with Go</title>
            <script src="/webui.js"></script>
            <style>
                body {
                    font-family: Arial, sans-serif;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    justify-content: center;
                    height: 100vh;
                    margin: 0;
                    background: linear-gradient(to right, #ece9e6, #ffffff);
                }
                h1 {
                    color: #333;
                    margin-bottom: 20px;
                }
                button {
                    padding: 10px 20px;
                    margin: 10px;
                    border: none;
                    border-radius: 5px;
                    background-color: #4CAF50;
                    color: white;
                    font-size: 16px;
                    cursor: pointer;
                    transition: background-color 0.3s ease;
                }
                button:hover {
                    background-color: #45a049;
                }
                button:active {
                    background-color: #3e8e41;
                }
            </style>
        </head>
        <body>
            <h1>Hello World from Go!</h1>
            <button id="OkButton">Ok</button>
        </body>
    </html>`)

    webui.Wait()
}

func onOkButtonClicked(e webui.Event) string {
    fileName := "events.txt"
    line := fmt.Sprintf("%s\n", time.Now())

    file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Println("Failed to open file:", err)
        return ""
    }
    defer file.Close()

    _, err = file.WriteString(line)
    if err != nil {
        fmt.Println("Failed to write to file:", err)
        return ""
    }
    return ""
}


Enter fullscreen mode Exit fullscreen mode

Build the application, go build, and then run it, ./go.webui.

This line:



window := webui.NewWindow()


Enter fullscreen mode Exit fullscreen mode

is creating our WebUI window object. Next step is to bind a function to the button with this line:



webui.Bind(window, "OkButton", onOkButtonClicked)


Enter fullscreen mode Exit fullscreen mode

The, onOkButtonClicked, function will be invoked everytime anyone is clicking on the button.



func onOkButtonClicked(e webui.Event) string {
    fileName := "events.txt"
    line := fmt.Sprintf("%s\n", time.Now())

    file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Println("Failed to open file:", err)
        return ""
    }
    defer file.Close()

    _, err = file.WriteString(line)
    if err != nil {
        fmt.Println("Failed to write to file:", err)
        return ""
    }
    return ""
}


Enter fullscreen mode Exit fullscreen mode

That function is responsible to append the value from time.Now() to the file events.txt. The, Show, function on the window object will show the actual GUI and which is defined as the second argument to the show function. As you can see the GUI is defined with regular CSS, HTML and JavaScript. We could have put all the HTML/CSS/JavaScript in separate files instead of inline it in the second parameter.



// Inline
webui.Show(window, "<html><script src=\"/webui.js\"> ... </html>")

// or with a file
webui.Show(window, "file.html")


Enter fullscreen mode Exit fullscreen mode

Finally we end the main function with webui.Wait(), this will make your application run until the user closes all visible windows or when calling exit().

You can read more about WebUI in their documentation. The project seems to be moving a lot since the documentation do not exactly look like the code above, the latest version of WebUI is not 2.4.0 anymore (I believe it's 2.4.2), but I used that version since it just worked on my machine without any problems.

It will be interesting to see how this project progress in the future and if you know the web UI stuff then this might be a great library to build GUI with.

Happy hacking!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .