It's increadably easy! Just installing all the dependencies and Wails itself,
which is described in their docs. After that you just inititialize a new project by
wails init
with the desired frontend framework (Svelte, Vue, React, Preact, Lit, or even just Vanilla).
Then it's possible to just write some Go and frontend code or
directly run wails dev
for a dev environment, which opens a native window containing the frontend,
or you could do wails build
to get the final binary executable.
err := wails.Run(&options.App{
Title: "Window title",
Width: 1024,
Height: 768,
MinWidth: 400,
MinHeight: 400,
Assets: assets,
BackgroundColour: &options.RGBA{R: 0, G: 0, B: 0, A: 1},
OnStartup: app.startup,
Bind: []interface{}{
app,
},
Mac: &mac.Options{
Appearance: mac.NSAppearanceNameDarkAqua,
WebviewIsTransparent: true,
WindowIsTranslucent: true,
About: &mac.AboutInfo{
Title: "GraphGuard Presentation",
Message: "© 2022 GraphGuard",
Icon: icon,
},
},
Windows: &windows.Options{
WebviewIsTransparent: true,
WindowIsTranslucent: true,
BackdropType: windows.Auto,
Theme: windows.SystemDefault,
},
/*Linux: &linux.Options{
Icon: [...], // the only availabe option for linux
},*/
})
Only certain options can be dynamically updated later, like height, width...
<script lang='ts'>
import SectionFibonacci from './SectionFibonacci.svelte'
import SectionEvents from './SectionEvents.svelte'
</script>
<main>
<svg id='Logo'>[...]</svg>
<SectionFibonacci/>
<SectionEvents/>
</main>
In the frontend events are handled kinda strage. There is an runtime endpoint called "EventsOn", by which you can listen on a certain event. Another endpoint called "EventsOff" is there to unsubscribe from the event by the given name. It doesn't only remove one listener, but of all of them. To keep the experience like we know it in JavaScript, we created our own event handler, which is only registering and removing certain listeners.
import {v4 as UUID} from 'uuid'
import {EventsOff, EventsOn} from '../wailsjs/runtime/runtime'
type Callback = ()=> void
class EventHandler {
private _events: {[eventName: string]: {[id: string]: Callback}} = {}
public on(eventName: string, fn: Callback): Callback {
if (
!this._events[eventName] ||
Object.keys(this._events[eventName]).length < 1
) {
this._events[eventName] = {}
EventsOn(eventName, (...args)=> {
const handlers = Object.values(this._events[eventName])
for (fn of handlers) {
fn.apply(this, args)
}
})
}
const id = UUID()
this._events[eventName][id] = fn
return ()=> {this.remove(eventName, id)}
}
public remove(eventName: string, id: string) {
delete this._events[eventName][id]
if (Object.keys(this._events[eventName]).length < 1) {
EventsOff(eventName)
}
}
}
export default new EventHandler()
Wails is still in a early stage, as it is missing quite a lot essential features, e.g. native context menus, zoom, notifications, and much more.
It's possible through build pipes in GitHub Actions, or even by Docker.
Every frontend developer knows what that means... we all love Safari. Honsetly it would be great to strictly set it to like Firefox or Chrome. As we tested on Linux (Ubuntu), we encountered that it's powered on Safari too. On Windows it's as expected Edge ("Chrome").
Wails could potentionally compile to WebAssembly, just without the OS functionalities. Like what if you offer a standalone version, but also use this app for your cloud service in the browser.
The conversion between Go structs and JSON. It generates JS Classes, where the constructor takes an untyped Object and just maps the values by the keys. First off all: Why JS Classes? What's their purpose? Secondly: Why to do this at all, when the constructor just takes an untyped object?
Native dialogs are too OS specific and therefore inconsistent. When defining 4 buttons (the total amount for macOS) then only macOS will show them, Linux will have just a default "Ok" button.
For now there are only two predefined menus: "About" and "Edit". Problem is, that both only work on macOS. The implementation is all up on you.
Calls to Go code go through websockets and incurring a cost. Calling a synchronous JavaScript function calculating the fibonacci number at 1.000 iterations will be faster than calling an analogous Go function due to the overhead. For more complex computations Go can be more efficient.
There is no access point to the DOM from Go. It's not possible to do something with the frontend, like with WebAssambly. Such desires would need to be handled by events.
As all features are OS dependent, it's hard to keep an universal look. The Transparent window feature is unfortunately unavailable for linux. On Windows 11 it's even possible to use different bluring techniques: Acrylic, the frosty looking like used in Windows 10, and Mica, which is used in Windows 11. Windows 10 and macOS only have a predefined default which can't be changed.
As seen on the screenshot, there is no text, it's invisible, but if you click it, it opens the corresponding menu.