mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 06:20:48 +08:00
docs: update binding sections
This commit is contained in:
parent
55855ccc4d
commit
f21c9ba880
@ -123,9 +123,10 @@ option [OnBeforeClose](reference/options.mdx#onbeforeclose).
|
|||||||
#### Method Binding
|
#### Method Binding
|
||||||
|
|
||||||
The `Bind` option is one of the most important options in a Wails application. It specifies which struct methods
|
The `Bind` option is one of the most important options in a Wails application. It specifies which struct methods
|
||||||
to expose to the frontend. When the application starts, it examines the struct instances listed in the `Bind` field in
|
to expose to the frontend. Think of structs like "controllers" in a traditional web application. When the application
|
||||||
the options, determines which methods are public (starts with an uppercase letter) and will generate Javascript versions
|
starts, it examines the struct instances listed in the `Bind` field in the options, determines which methods are
|
||||||
of those methods that can be called by the frontend code.
|
public (starts with an uppercase letter) and will generate Javascript versions of those methods that can be called
|
||||||
|
by the frontend code.
|
||||||
|
|
||||||
:::info Note
|
:::info Note
|
||||||
|
|
||||||
@ -158,8 +159,6 @@ func main() {
|
|||||||
Width: 1024,
|
Width: 1024,
|
||||||
Height: 768,
|
Height: 768,
|
||||||
Assets: &assets,
|
Assets: &assets,
|
||||||
OnStartup: app.startup,
|
|
||||||
OnShutdown: app.shutdown,
|
|
||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
app,
|
||||||
},
|
},
|
||||||
@ -174,67 +173,41 @@ type App struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *App) startup(ctx context.Context) {
|
func (a *App) Greet(name string) string {
|
||||||
b.ctx = ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *App) shutdown(ctx context.Context) {}
|
|
||||||
|
|
||||||
func (b *App) Greet(name string) string {
|
|
||||||
return fmt.Sprintf("Hello %s!", name)
|
return fmt.Sprintf("Hello %s!", name)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You may bind as many structs as you like. Just make sure you create an instance of it and pass it in `Bind`:
|
You may bind as many structs as you like. Just make sure you create an instance of it and pass it in `Bind`:
|
||||||
|
|
||||||
```go {10-12}
|
```go {8-10}
|
||||||
...
|
//...
|
||||||
err := wails.Run(&options.App{
|
err := wails.Run(&options.App{
|
||||||
Title: "Basic Demo",
|
Title: "Basic Demo",
|
||||||
Width: 1024,
|
Width: 1024,
|
||||||
Height: 768,
|
Height: 768,
|
||||||
Assets: &assets,
|
Assets: &assets,
|
||||||
OnStartup: app.startup,
|
|
||||||
OnShutdown: app.shutdown,
|
|
||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
app,
|
||||||
&mystruct1{},
|
&mystruct1{},
|
||||||
&mystruct2{},
|
&mystruct2{},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The bound methods are located in the frontend at `window.go.<packagename>.<struct>.<method>`.
|
When you run `wails dev` (or `wails generate module`), a frontend module will be generated containing the following:
|
||||||
In the example above, we bind `app`, which has one public method `Greet`.
|
- Javascript bindings for all bound methods
|
||||||
This can be called in Javascript by calling `window.go.main.App.Greet`.
|
- Typescript declarations for all bound methods
|
||||||
These methods return a Promise. A successful call will result in the first return value from the Go call to be passed
|
- Typescript definitions for all Go structs used as inputs or outputs by the bound methods
|
||||||
to the `resolve` handler. An unsuccessful call is when a Go method that has an error type as it's second return value,
|
|
||||||
passes an error instance back to the caller. This is passed back via the `reject` handler.
|
|
||||||
In the example above, `Greet` only returns a `string` so the Javascript call will never reject - unless invalid data
|
|
||||||
is passed to it.
|
|
||||||
|
|
||||||
All data types are correctly translated between Go and Javascript. Even structs. If you return a struct from a Go call,
|
This makes it incredibly simple to call Go code from the frontend, using the same strongly typed datastructures.
|
||||||
it will be returned to your frontend as a Javascript map. Note: If you wish to use structs, you **must** define `json` struct
|
|
||||||
tags for your fields!
|
|
||||||
|
|
||||||
:::info Note
|
|
||||||
Anonymous nested structs are not supported at this time.
|
|
||||||
:::
|
|
||||||
|
|
||||||
It is also possible to send structs back to Go. Any Javascript map passed as an argument that
|
|
||||||
is expecting a struct, will be converted to that struct type. To make this process a lot easier, in `dev` mode,
|
|
||||||
a TypeScript module is generated, defining all the struct types used in bound methods. Using this module, it's possible
|
|
||||||
to construct and send native Javascript objects to the Go code.
|
|
||||||
|
|
||||||
More information on Binding can be found in the [Binding Methods](guides/application-development.mdx#binding-methods)
|
|
||||||
section of the [Application Development Guide](guides/application-development.mdx).
|
|
||||||
|
|
||||||
## The Frontend
|
## The Frontend
|
||||||
|
|
||||||
### Overview
|
### Overview
|
||||||
|
|
||||||
The frontend is a collection of files rendered by webkit. It's like a browser and webserver in one.
|
The frontend is a collection of files rendered by webkit. It''s like a browser and webserver in one.
|
||||||
There is virtually[^1] no limit to which frameworks or libraries you can use. The main points of interaction between
|
There is virtually[^1] no limit to which frameworks or libraries you can use. The main points of interaction between
|
||||||
the frontend and your Go code are:
|
the frontend and your Go code are:
|
||||||
|
|
||||||
@ -247,48 +220,61 @@ the frontend and your Go code are:
|
|||||||
|
|
||||||
### Calling bound Go methods
|
### Calling bound Go methods
|
||||||
|
|
||||||
All bound Go methods are available at `window.go.<package>.<struct>.<method>`. As stated in
|
When you run your application with `wails dev`, it will automatically generate Javascript bindings for your structs in a
|
||||||
the previous section, these return a Promise where a successful call returns a value to the
|
directory called `wailsjs/go` (You can also do this by running `wails generate module`). The generated files mirror the
|
||||||
resolve handler and an error returns a value to the reject handler.
|
package names in your application. In the example above, we bind `app`, which has one public method `Greet`. This will
|
||||||
|
lead to the generation of the following files:
|
||||||
|
|
||||||
```go title="mycode.js"
|
```bash
|
||||||
window.go.main.App.Greet("Bill").then((result) => {
|
wailsjs
|
||||||
console.log("The greeting is: " + result);
|
└─go
|
||||||
})
|
└─main
|
||||||
|
├─App.d.ts
|
||||||
|
└─App.js
|
||||||
|
```
|
||||||
|
Here we can see that there is a `main` package that contains the Javascript bindings for the bound `App` struct, as well
|
||||||
|
as the Typescript declaration file for those methods. To call `Greet` from our frontend, we simply import the method and
|
||||||
|
call it like a regular Javascript function:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ...
|
||||||
|
import {Greet} from '../wailsjs/go/main/App'
|
||||||
|
|
||||||
|
function doGreeting(name) {
|
||||||
|
Greet(name).then((result) => {
|
||||||
|
// Do something with result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The Typescript declaration file gives you the correct types for the bound methods:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export function Greet(arg1:string):Promise<string>;
|
||||||
```
|
```
|
||||||
|
|
||||||
When running the application in `dev` mode, a javascript module is generated that wraps these
|
The generated methods return a Promise. A successful call will result in the first return value from the Go call to be passed
|
||||||
methods with JSDoc annotations. This really help with development, especially as most
|
to the `resolve` handler. An unsuccessful call is when a Go method that has an error type as it''s second return value,
|
||||||
IDEs will process JSDoc to provide code completion and type hinting. This module is called `go`
|
passes an error instance back to the caller. This is passed back via the `reject` handler.
|
||||||
and is generated in the directory specified by the `wailsjsdir` flag. In this module is a file
|
In the example above, `Greet` only returns a `string` so the Javascript call will never reject - unless invalid data
|
||||||
called `bindings.js` containing these wrappers. For the above example, the file contains the
|
is passed to it.
|
||||||
following code:
|
|
||||||
|
|
||||||
```js title="bindings.js"
|
All data types are correctly translated between Go and Javascript. Even structs. If you return a struct from a Go call,
|
||||||
const go = {
|
it will be returned to your frontend as a Javascript class. Note: If you wish to use structs, you **must** define
|
||||||
main: {
|
`json` struct tags for your fields!
|
||||||
App: {
|
|
||||||
/**
|
|
||||||
* Greet
|
|
||||||
* @param {Person} arg1 - Go Type: string
|
|
||||||
* @returns {Promise<string>} - Go Type: string
|
|
||||||
*/
|
|
||||||
Greet: (arg1) => {
|
|
||||||
return window.go.main.App.Greet(arg1);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export default go;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Support for structs
|
:::info Note
|
||||||
|
Anonymous nested structs are not supported at this time.
|
||||||
|
:::
|
||||||
|
|
||||||
There is also additional support for Go methods that use structs in their signature. All Go structs
|
It is possible to send structs back to Go. Any Javascript map/class passed as an argument that
|
||||||
specified by bound method (either as parameters or return types) will have Typescript versions auto
|
is expecting a struct, will be converted to that struct type. To make this process a lot easier, in `dev` mode,
|
||||||
generated as part of the Go code wrapper module. Using these, it's possible to share the same data
|
a TypeScript module is generated, defining all the struct types used in bound methods. Using this module, it''s possible
|
||||||
model between Go and Javascript. These models align with the JSDoc annotations, empowering IDE code
|
to construct and send native Javascript objects to the Go code.
|
||||||
completion.
|
|
||||||
|
There is also support for Go methods that use structs in their signature. All Go structs
|
||||||
|
specified by a bound method (either as parameters or return types) will have Typescript versions auto
|
||||||
|
generated as part of the Go code wrapper module. Using these, it''s possible to share the same data
|
||||||
|
model between Go and Javascript.
|
||||||
|
|
||||||
Example: We update our `Greet` method to accept a `Person` instead of a string:
|
Example: We update our `Greet` method to accept a `Person` instead of a string:
|
||||||
|
|
||||||
@ -309,76 +295,77 @@ func (a *App) Greet(p Person) string {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Our `bindings.js` file has now been updated to reflect the change:
|
The `wailsjs/go/main/App.js` file will still have the following code:
|
||||||
|
|
||||||
```js title="bindings.js"
|
```js title="App.js"
|
||||||
const go = {
|
export function Greet(arg1) {
|
||||||
main: {
|
return window['go']['main']['App']['Greet'](arg1);
|
||||||
App: {
|
}
|
||||||
/**
|
|
||||||
* Greet
|
|
||||||
* @param {Person} arg1 - Go Type: main.Person
|
|
||||||
* @returns {Promise<string>} - Go Type: string
|
|
||||||
*/
|
|
||||||
Greet: (arg1) => {
|
|
||||||
return window.go.main.App.Greet(arg1);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export default go;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Alongside `bindings.js`, there is a file called `models.ts`. This contains our Go structs in TypeScript form:
|
But the `wailsjs/go/main/App.d.ts` file will be updated with the following code:
|
||||||
|
|
||||||
|
```ts title="App.d.ts"
|
||||||
|
import {main} from '../models';
|
||||||
|
|
||||||
|
export function Greet(arg1:main.Person):Promise<string>;
|
||||||
|
```
|
||||||
|
|
||||||
|
As we can see, the "main" namespace is imported from a new "models.ts" file. This file contains all the struct definitions
|
||||||
|
used by our bound methods. In this example, this is a `Person` struct. If we look at `models.ts`, we can see how the models
|
||||||
|
are defined:
|
||||||
|
|
||||||
```ts title="models.ts"
|
```ts title="models.ts"
|
||||||
export class Address {
|
export namespace main {
|
||||||
street: string;
|
|
||||||
postcode: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
export class Address {
|
||||||
return new Address(source);
|
street: string;
|
||||||
}
|
postcode: string;
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
if ("string" === typeof source) source = JSON.parse(source);
|
return new Address(source);
|
||||||
this.street = source["street"];
|
}
|
||||||
this.postcode = source["postcode"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Person {
|
|
||||||
name: string;
|
|
||||||
age: number;
|
|
||||||
address?: Address;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
constructor(source: any = {}) {
|
||||||
return new Person(source);
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
}
|
this.street = source["street"];
|
||||||
|
this.postcode = source["postcode"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class Person {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
address?: Address;
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
if ("string" === typeof source) source = JSON.parse(source);
|
return new Person(source);
|
||||||
this.name = source["name"];
|
}
|
||||||
this.age = source["age"];
|
|
||||||
this.address = this.convertValues(source["address"], Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
constructor(source: any = {}) {
|
||||||
if (!a) {
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
return a;
|
this.name = source["name"];
|
||||||
}
|
this.age = source["age"];
|
||||||
if (a.slice) {
|
this.address = this.convertValues(source["address"], Address);
|
||||||
return (a as any[]).map((elem) => this.convertValues(elem, classs));
|
}
|
||||||
} else if ("object" === typeof a) {
|
|
||||||
if (asMap) {
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
for (const key of Object.keys(a)) {
|
if (!a) {
|
||||||
a[key] = new classs(a[key]);
|
return a;
|
||||||
}
|
}
|
||||||
return a;
|
if (a.slice) {
|
||||||
}
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
return new classs(a);
|
} else if ("object" === typeof a) {
|
||||||
}
|
if (asMap) {
|
||||||
return a;
|
for (const key of Object.keys(a)) {
|
||||||
}
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -386,22 +373,23 @@ So long as you have TypeScript as part of your frontend build configuration, you
|
|||||||
the following way:
|
the following way:
|
||||||
|
|
||||||
```js title="mycode.js"
|
```js title="mycode.js"
|
||||||
import go from "./wailsjs/go/bindings";
|
import {Greet} from '../wailsjs/go/main/App'
|
||||||
import { Person } from "./wailsjs/go/models";
|
import {main} from '../wailsjs/go/models'
|
||||||
|
|
||||||
let name = "";
|
function generate() {
|
||||||
|
let person = new main.Person()
|
||||||
function greet(name) {
|
person.name = "Peter"
|
||||||
let p = new Person();
|
person.age = 27
|
||||||
p.name = name;
|
Greet(person).then((result) => {
|
||||||
p.age = 42;
|
console.log(result)
|
||||||
go.main.App.Greet(p).then((result) => {
|
})
|
||||||
console.log(result);
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The combination of JSDoc and TypeScript generated models makes for a powerful development environment.
|
The combination of generated bindings and TypeScript models makes for a powerful development environment.
|
||||||
|
|
||||||
|
More information on Binding can be found in the [Binding Methods](guides/application-development.mdx#binding-methods)
|
||||||
|
section of the [Application Development Guide](guides/application-development.mdx).
|
||||||
|
|
||||||
### Calling runtime methods
|
### Calling runtime methods
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user