mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-05 05:21:03 +08:00
456 lines
15 KiB
Markdown
456 lines
15 KiB
Markdown
# Changes for v3
|
|
|
|
!!! note
|
|
This is currently an unsorted brain dump of changes. It will be
|
|
organised into a more readable format soon.
|
|
|
|
## Options
|
|
|
|
The application options have been revised since v2.
|
|
|
|
## Events
|
|
|
|
In v3, there are 3 types of events:
|
|
|
|
- Application Events
|
|
- Window Events
|
|
- Custom Events
|
|
|
|
### Application Events
|
|
|
|
Application events are events that are emitted by the application. These events
|
|
include native events such as `ApplicationDidFinishLaunching` on macOS.
|
|
|
|
### Window Events
|
|
|
|
Window events are events that are emitted by a window. These events include
|
|
native events such as `WindowDidBecomeMain` on macOS. Common events are also
|
|
defined, so they work cross-platform, e.g. `WindowClosing`.
|
|
|
|
### Custom Events
|
|
|
|
Events that the user defines are called `WailsEvents`. This is to differentiate
|
|
them from the `Event` object that is used to communicate with the browser.
|
|
WailsEvents are now objects that encapsulate all the details of an event. This
|
|
includes the event name, the data, and the source of the event.
|
|
|
|
The data associated with a WailsEvent is now a single value. If multiple values
|
|
are required, then a struct can be used.
|
|
|
|
### Event callbacks and `Emit` function signature
|
|
|
|
The signatures events callbacks (as used by `On`, `Once` & `OnMultiple`) have
|
|
changed. In v2, the callback function received optional data. In v3, the
|
|
callback function receives a `WailsEvent` object that contains all data related
|
|
to the event.
|
|
|
|
Similarly, the `Emit` function has changed. Instead of taking a name and
|
|
optional data, it now takes a single `WailsEvent` object that it will emit.
|
|
|
|
### `Off` and `OffAll`
|
|
|
|
In v2, `Off` and `OffAll` calls would remove events in both JS and Go. Due to
|
|
the multi-window nature of v3, this has been changed so that these methods only
|
|
apply to the context they are called in. For example, if you call `Off` in a
|
|
window, it will only remove events for that window. If you use `Off` in Go, it
|
|
will only remove events for Go.
|
|
|
|
### Hooks
|
|
|
|
Event Hooks are a new feature in v3. They allow you to hook into the event
|
|
system and perform actions when certain events are emitted. For example, you can
|
|
hook into the `WindowClosing` event and perform some cleanup before the window
|
|
closes. Hooks can be registered at the application level or at the window level
|
|
using `RegisterHook`. Application level are for application events. Window level
|
|
hooks will only be called for the window they are registered with.
|
|
|
|
### Logging
|
|
|
|
Logging in v2 was confusing as both application logs and system (internal) logs
|
|
were using the same logger. We have simplified this as follows:
|
|
|
|
- Internal logs are now handled using the standard Go `slog` logger. This is
|
|
configured using the `logger` option in the application options. By default,
|
|
this uses the [tint](https://github.com/lmittmann/tint) logger.
|
|
- Application logs can now be achieved through the new `log` plugin which
|
|
utilises `slog` under the hood. This plugin provides a simple API for logging
|
|
to the console. It is available in both Go and JS.
|
|
|
|
### Developer notes
|
|
|
|
When emitting an event in Go, it will dispatch the event to local Go listeners
|
|
and also each window in the application. When emitting an event in JS, it now
|
|
sends the event to the application. This will be processed as if it was emitted
|
|
in Go, however the sender ID will be that of the window.
|
|
|
|
## Window
|
|
|
|
The Window API has largely remained the same, however the methods are now on an
|
|
instance of a window rather than the runtime. Some notable differences are:
|
|
|
|
- Windows now have a Name that identifies them. This is used to identify the
|
|
window when emitting events.
|
|
- Windows have even more methods on the that were previously unavailable, such
|
|
as `AbsolutePosition` and `ToggleDevTools`.
|
|
- Windows can now accept files via native drag and drop. See the Drag and Drop
|
|
section for more details.
|
|
|
|
## ClipBoard
|
|
|
|
The clipboard API has been simplified. There is now a single `Clipboard` object
|
|
that can be used to read and write to the clipboard. The `Clipboard` object is
|
|
available in both Go and JS. `SetText()` to set the text and `Text()` to get the
|
|
text.
|
|
|
|
## Bindings
|
|
|
|
Bindings work in a similar way to v2, by providing a means to bind struct
|
|
methods to the frontend. These can be called in the frontend using the binding
|
|
wrappers generated by the `wails3 generate bindings` command:
|
|
|
|
```javascript
|
|
// @ts-check
|
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
|
// This file is automatically generated. DO NOT EDIT
|
|
|
|
import { main } from "./models";
|
|
|
|
window.go = window.go || {};
|
|
window.go.main = {
|
|
GreetService: {
|
|
/**
|
|
* GreetService.Greet
|
|
* Greet greets a person
|
|
* @param name {string}
|
|
* @returns {Promise<string>}
|
|
**/
|
|
Greet: function (name) {
|
|
wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0));
|
|
},
|
|
|
|
/**
|
|
* GreetService.GreetPerson
|
|
* GreetPerson greets a person
|
|
* @param person {main.Person}
|
|
* @returns {Promise<string>}
|
|
**/
|
|
GreetPerson: function (person) {
|
|
wails.CallByID(4021313248, ...Array.prototype.slice.call(arguments, 0));
|
|
},
|
|
},
|
|
};
|
|
```
|
|
|
|
Bound methods are obfuscated by default, and are identified using uint32 IDs,
|
|
calculated using the
|
|
[FNV hashing algorithm](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function).
|
|
This is to prevent the method name from being exposed in production builds. In
|
|
debug mode, the method IDs are logged along with the calculated ID of the method
|
|
to aid in debugging. If you wish to add an extra layer of obfuscation, you can
|
|
use the `BindAliases` option. This allows you to specify a map of alias IDs to
|
|
method IDs. When the frontend calls a method using an ID, the method ID will be
|
|
looked up in the alias map first for a match. If it does not find it, it assumes
|
|
it's a standard method ID and tries to find the method in the usual way.
|
|
|
|
Example:
|
|
|
|
```go
|
|
app := application.New(application.Options{
|
|
Bind: []any{
|
|
&GreetService{},
|
|
},
|
|
BindAliases: map[uint32]uint32{
|
|
1: 1411160069,
|
|
2: 4021313248,
|
|
},
|
|
Assets: application.AssetOptions{
|
|
FS: assets,
|
|
},
|
|
Mac: application.MacOptions{
|
|
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
|
},
|
|
})
|
|
```
|
|
|
|
We can now call using this alias in the frontend: `wails.Call(1, "world!")`.
|
|
|
|
### Insecure calls
|
|
|
|
If you don't mind your calls being available in plain text in your binary and
|
|
have no intention of using [garble](https://github.com/burrowers/garble), then
|
|
you can use the insecure `wails.CallByName()` method. This method takes the
|
|
fully qualified name of the method to call and the arguments to pass to it.
|
|
Example:
|
|
|
|
```go
|
|
wails.CallByName("main.GreetService.Greet", "world!")
|
|
```
|
|
|
|
!!! danger
|
|
|
|
This is only provided as a convenience method for development. It is not recommended to use this in production.
|
|
|
|
## Dialogs
|
|
|
|
Dialogs are now available in JavaScript!
|
|
|
|
### Windows
|
|
|
|
Dialog buttons in Windows are not configurable and are constant depending on the
|
|
type of dialog. To trigger a callback when a button is pressed, create a button
|
|
with the same name as the button you wish to have the callback attached to.
|
|
Example: Create a button with the label `Ok` and use `OnClick()` to set the
|
|
callback method:
|
|
|
|
```go
|
|
dialog := app.QuestionDialog().
|
|
SetTitle("Update").
|
|
SetMessage("The cancel button is selected when pressing escape")
|
|
ok := dialog.AddButton("Ok")
|
|
ok.OnClick(func() {
|
|
// Do something
|
|
})
|
|
no := dialog.AddButton("Cancel")
|
|
dialog.SetDefaultButton(ok)
|
|
dialog.SetCancelButton(no)
|
|
dialog.Show()
|
|
```
|
|
|
|
## Drag and Drop
|
|
|
|
Native drag and drop can be enabled per-window. Simply set the
|
|
`EnableDragAndDrop` window config option to `true` and the window will allow
|
|
files to be dragged onto it. When this happens, the `events.FilesDropped` event
|
|
will be emitted. The filenames can then be retrieved from the
|
|
`WindowEvent.Context()` using the `DroppedFiles()` method. This returns a slice
|
|
of strings containing the filenames.
|
|
|
|
## Context Menus
|
|
|
|
Context menus are contextual menus that are shown when the user right-clicks on
|
|
an element. Creating a context menu is the same as creating a standard menu , by
|
|
using `app.NewMenu()`. To make the context menu available to a window, call
|
|
`window.RegisterContextMenu(name, menu)`. The name will be the id of the context
|
|
menu and used by the frontend.
|
|
|
|
To indicate that an element has a context menu, add the `data-contextmenu`
|
|
attribute to the element. The value of this attribute should be the name of a
|
|
context menu previously registered with the window.
|
|
|
|
It is possible to register a context menu at the application level, making it
|
|
available to all windows. This can be done using
|
|
`app.RegisterContextMenu(name, menu)`. If a context menu cannot be found at the
|
|
window level, the application context menus will be checked. A demo of this can
|
|
be found in `v3/examples/contextmenus`.
|
|
|
|
## Wails Markup Language (WML)
|
|
|
|
The Wails Markup Language is a simple markup language that allows you to add
|
|
functionality to standard HTML elements without the use of Javascript.
|
|
|
|
The following tags are currently supported:
|
|
|
|
### `data-wml-event`
|
|
|
|
This specifies that a Wails event will be emitted when the element is clicked.
|
|
The value of the attribute should be the name of the event to emit.
|
|
|
|
Example:
|
|
|
|
```html
|
|
<button data-wml-event="myevent">Click Me</button>
|
|
```
|
|
|
|
Sometimes you need the user to confirm an action. This can be done by adding the
|
|
`data-wml-confirm` attribute to the element. The value of this attribute will be
|
|
the message to display to the user.
|
|
|
|
Example:
|
|
|
|
```html
|
|
<button data-wml-event="delete-all-items" data-wml-confirm="Are you sure?">
|
|
Delete All Items
|
|
</button>
|
|
```
|
|
|
|
### `data-wml-window`
|
|
|
|
Any `wails.window` method can be called by adding the `data-wml-window`
|
|
attribute to an element. The value of the attribute should be the name of the
|
|
method to call. The method name should be in the same case as the method.
|
|
|
|
```html
|
|
<button data-wml-window="Close">Close Window</button>
|
|
```
|
|
|
|
### `data-wml-trigger`
|
|
|
|
This attribute specifies which javascript event should trigger the action. The
|
|
default is `click`.
|
|
|
|
```html
|
|
<button data-wml-event="hover-box" data-wml-trigger="mouseover">
|
|
Hover over me!
|
|
</button>
|
|
```
|
|
|
|
## Systray
|
|
|
|
Wails 3 comes with a built-in systray. This is a fully featured systray that has
|
|
been designed to be as simple as possible to use. It is possible to set the
|
|
icon, tooltip and menu of the systray. It is possible to also "attach" a window
|
|
to the systray. Doing this will provide the following functionality:
|
|
|
|
- Clicking the systray icon with toggle the window visibility
|
|
- Right-clicking the systray will open the menu, if there is one
|
|
|
|
On macOS, if there is no attached window, the systray will use the default
|
|
method of displaying the menu (any button). If there is an attached window but
|
|
no menu, the systray will toggle the window regardless of the button pressed.
|
|
|
|
## Plugins
|
|
|
|
Plugins are a way to extend the functionality of your Wails application.
|
|
|
|
### Creating a plugin
|
|
|
|
Plugins are standard Go structure that adhere to the following interface:
|
|
|
|
```go
|
|
type Plugin interface {
|
|
Name() string
|
|
Init(*application.App) error
|
|
Shutdown()
|
|
CallableByJS() []string
|
|
InjectJS() string
|
|
}
|
|
```
|
|
|
|
The `Name()` method returns the name of the plugin. This is used for logging
|
|
purposes.
|
|
|
|
The `Init(*application.App) error` method is called when the plugin is loaded.
|
|
The `*application.App` parameter is the application that the plugin is being
|
|
loaded into. Any errors will prevent the application from starting.
|
|
|
|
The `Shutdown()` method is called when the application is shutting down.
|
|
|
|
The `CallableByJS()` method returns a list of exported functions that can be
|
|
called from the frontend. These method names must exactly match the names of the
|
|
methods exported by the plugin.
|
|
|
|
The `InjectJS()` method returns JavaScript that should be injected into all
|
|
windows as they are created. This is useful for adding custom JavaScript
|
|
functions that complement the plugin.
|
|
|
|
### Tips
|
|
|
|
#### Enums
|
|
|
|
In Go, enums are often defined as a type and a set of constants. For example:
|
|
|
|
```go
|
|
type MyEnum int
|
|
|
|
const (
|
|
MyEnumOne MyEnum = iota
|
|
MyEnumTwo
|
|
MyEnumThree
|
|
)
|
|
```
|
|
|
|
Due to incompatibility between Go and JavaScript, custom types cannot be used in
|
|
this way. The best strategy is to use a type alias for float64:
|
|
|
|
```go
|
|
type MyEnum = float64
|
|
|
|
const (
|
|
MyEnumOne MyEnum = iota
|
|
MyEnumTwo
|
|
MyEnumThree
|
|
)
|
|
```
|
|
|
|
In Javascript, you can then use the following:
|
|
|
|
```js
|
|
const MyEnum = {
|
|
MyEnumOne: 0,
|
|
MyEnumTwo: 1,
|
|
MyEnumThree: 2,
|
|
};
|
|
```
|
|
|
|
- Why use `float64`? Can't we use `int`?
|
|
- Because JavaScript doesn't have a concept of `int`. Everything is a
|
|
`number`, which translates to `float64` in Go. There are also restrictions
|
|
on casting types in Go's reflection package, which means using `int` doesn't
|
|
work.
|
|
|
|
### BackgroundColour
|
|
|
|
In v2, this was a pointer to an `RGBA` struct. In v3, this is an `RGBA` struct
|
|
value.
|
|
|
|
### WindowIsTranslucent
|
|
|
|
This flag has been removed. Now there is a `BackgroundType` flag that can be
|
|
used to set the type of background the window should have. This flag can be set
|
|
to any of the following values:
|
|
|
|
- `BackgroundTypeSolid` - The window will have a solid background
|
|
- `BackgroundTypeTransparent` - The window will have a transparent background
|
|
- `BackgroundTypeTranslucent` - The window will have a translucent background
|
|
|
|
On Windows, if the `BackgroundType` is set to `BackgroundTypeTranslucent`, the
|
|
type of translucency can be set using the `BackdropType` flag in the
|
|
`WindowsWindow` options. This can be set to any of the following values:
|
|
|
|
- `Auto` - The window will use an effect determined by the system
|
|
- `None` - The window will have no background
|
|
- `Mica` - The window will use the Mica effect
|
|
- `Acrylic` - The window will use the acrylic effect
|
|
- `Tabbed` - The window will use the tabbed effect
|
|
|
|
## Windows Application Options
|
|
|
|
### WndProcInterceptor
|
|
|
|
If this is set, the WndProc will be intercepted and the function will be called.
|
|
This allows you to handle Windows messages directly. The function should have
|
|
the following signature:
|
|
|
|
```go
|
|
func(hwnd uintptr, msg uint32, wParam, lParam uintptr) (returnValue uintptr, shouldReturn)
|
|
```
|
|
|
|
The `shouldReturn` value should be set to `true` if the returnValue should be
|
|
returned by the main wndProc method. If it is set to `false`, the return value
|
|
will be ignored and the message will continue to be processed by the main
|
|
wndProc method.
|
|
|
|
## Hide Window on Close + OnBeforeClose
|
|
|
|
In v2, there was the `HideWindowOnClose` flag to hide the window when it closed.
|
|
There was a logical overlap between this flag and the `OnBeforeClose` callback.
|
|
In v3, the `HideWindowOnClose` flag has been removed and the `OnBeforeClose`
|
|
callback has been renamed to `ShouldClose`. The `ShouldClose` callback is called
|
|
when the user attempts to close a window. If the callback returns `true`, the
|
|
window will close. If it returns `false`, the window will not close. This can be
|
|
used to hide the window instead of closing it.
|
|
|
|
## Window Drag
|
|
|
|
In v2, the `--wails-drag` attribute was used to indicate that an element could
|
|
be used to drag the window. In v3, this has been replaced with
|
|
`--webkit-app-region` to be more in line with the way other frameworks handle
|
|
this. The `--webkit-app-region` attribute can be set to any of the following
|
|
values:
|
|
|
|
- `drag` - The element can be used to drag the window
|
|
- `no-drag` - The element cannot be used to drag the window
|
|
|
|
We would have ideally liked to use `app-region`, however this is not supported
|
|
by the `getComputedStyle` call on webkit on macOS.
|