343 lines
8 KiB
Text
343 lines
8 KiB
Text
---
|
|
title: Advanced Binding
|
|
description: Advanced binding techniques including directives, code injection, and custom IDs
|
|
sidebar:
|
|
order: 3
|
|
---
|
|
|
|
import { FileTree } from "@astrojs/starlight/components";
|
|
|
|
This guide covers advanced techniques for customizing and optimizing the binding generation process in Wails v3.
|
|
|
|
## Customizing Generated Code with Directives
|
|
|
|
### Injecting Custom Code
|
|
|
|
The `//wails:inject` directive allows you to inject custom JavaScript/TypeScript code into the generated bindings:
|
|
|
|
```go
|
|
//wails:inject console.log("Hello from Wails!");
|
|
type MyService struct {}
|
|
|
|
func (s *MyService) Greet(name string) string {
|
|
return "Hello, " + name
|
|
}
|
|
```
|
|
|
|
This will inject the specified code into the generated JavaScript/TypeScript file for the `MyService` service.
|
|
|
|
You can also use conditional injection to target specific output formats:
|
|
|
|
```go
|
|
//wails:inject j*:console.log("Hello JS!"); // JavaScript only
|
|
//wails:inject t*:console.log("Hello TS!"); // TypeScript only
|
|
```
|
|
|
|
### Including Additional Files
|
|
|
|
The `//wails:include` directive allows you to include additional files with the generated bindings:
|
|
|
|
```go
|
|
//wails:include js/*.js
|
|
package mypackage
|
|
```
|
|
|
|
This directive is typically used in package documentation comments to include additional JavaScript/TypeScript files with the generated bindings.
|
|
|
|
### Marking Internal Types and Methods
|
|
|
|
The `//wails:internal` directive marks a type or method as internal, preventing it from being exported to the frontend:
|
|
|
|
```go
|
|
//wails:internal
|
|
type InternalModel struct {
|
|
Field string
|
|
}
|
|
|
|
//wails:internal
|
|
func (s *MyService) InternalMethod() {}
|
|
```
|
|
|
|
This is useful for types and methods that are only used internally by your Go code and should not be exposed to the frontend.
|
|
|
|
### Ignoring Methods
|
|
|
|
The `//wails:ignore` directive completely ignores a method during binding generation:
|
|
|
|
```go
|
|
//wails:ignore
|
|
func (s *MyService) IgnoredMethod() {}
|
|
```
|
|
|
|
This is similar to `//wails:internal`, but it completely ignores the method rather than marking it as internal.
|
|
|
|
### Custom Method IDs
|
|
|
|
The `//wails:id` directive specifies a custom ID for a method, overriding the default hash-based ID:
|
|
|
|
```go
|
|
//wails:id 42
|
|
func (s *MyService) CustomIDMethod() {}
|
|
```
|
|
|
|
This can be useful for maintaining compatibility when refactoring code.
|
|
|
|
## Working with Complex Types
|
|
|
|
### Nested Structs
|
|
|
|
The binding generator handles nested structs automatically:
|
|
|
|
```go
|
|
type Address struct {
|
|
Street string
|
|
City string
|
|
State string
|
|
Zip string
|
|
}
|
|
|
|
type Person struct {
|
|
Name string
|
|
Address Address
|
|
}
|
|
|
|
func (s *MyService) GetPerson() Person {
|
|
return Person{
|
|
Name: "John Doe",
|
|
Address: Address{
|
|
Street: "123 Main St",
|
|
City: "Anytown",
|
|
State: "CA",
|
|
Zip: "12345",
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
The generated JavaScript/TypeScript code will include classes for both `Person` and `Address`.
|
|
|
|
### Maps and Slices
|
|
|
|
Maps and slices are also handled automatically:
|
|
|
|
```go
|
|
type Person struct {
|
|
Name string
|
|
Attributes map[string]string
|
|
Friends []string
|
|
}
|
|
|
|
func (s *MyService) GetPerson() Person {
|
|
return Person{
|
|
Name: "John Doe",
|
|
Attributes: map[string]string{
|
|
"hair": "brown",
|
|
"eyes": "blue",
|
|
},
|
|
Friends: []string{"Jane", "Bob", "Alice"},
|
|
}
|
|
}
|
|
```
|
|
|
|
In JavaScript, maps are represented as objects and slices as arrays. In TypeScript, maps are represented as `Record<K, V>` and slices as `T[]`.
|
|
|
|
### Generic Types
|
|
|
|
The binding generator supports generic types:
|
|
|
|
```go
|
|
type Result[T any] struct {
|
|
Data T
|
|
Error string
|
|
}
|
|
|
|
func (s *MyService) GetResult() Result[string] {
|
|
return Result[string]{
|
|
Data: "Hello, World!",
|
|
Error: "",
|
|
}
|
|
}
|
|
```
|
|
|
|
The generated TypeScript code will include a generic class for `Result`:
|
|
|
|
```typescript
|
|
export class Result<T> {
|
|
"Data": T;
|
|
"Error": string;
|
|
|
|
constructor(source: Partial<Result<T>> = {}) {
|
|
if (!("Data" in source)) {
|
|
this["Data"] = null as any;
|
|
}
|
|
if (!("Error" in source)) {
|
|
this["Error"] = "";
|
|
}
|
|
|
|
Object.assign(this, source);
|
|
}
|
|
|
|
static createFrom<T>(source: string | object = {}): Result<T> {
|
|
let parsedSource = typeof source === "string" ? JSON.parse(source) : source;
|
|
return new Result<T>(parsedSource as Partial<Result<T>>);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Interfaces
|
|
|
|
The binding generator can generate TypeScript interfaces instead of classes using the `-i` flag:
|
|
|
|
```bash
|
|
wails3 generate bindings -ts -i
|
|
```
|
|
|
|
This will generate TypeScript interfaces for all models:
|
|
|
|
```typescript
|
|
export interface Person {
|
|
Name: string;
|
|
Attributes: Record<string, string>;
|
|
Friends: string[];
|
|
}
|
|
```
|
|
|
|
## Optimizing Binding Generation
|
|
|
|
### Using Names Instead of IDs
|
|
|
|
By default, the binding generator uses hash-based IDs for method calls. You can use the `-names` flag to use names instead:
|
|
|
|
```bash
|
|
wails3 generate bindings -names
|
|
```
|
|
|
|
This will generate code that uses method names instead of IDs:
|
|
|
|
```javascript
|
|
export function Greet(name) {
|
|
let $resultPromise = $Call.ByName("Greet", name);
|
|
return $resultPromise;
|
|
}
|
|
```
|
|
|
|
This can make the generated code more readable and easier to debug, but it may be slightly less efficient.
|
|
|
|
### Bundling the Runtime
|
|
|
|
By default, the generated code imports the Wails runtime from the `@wailsio/runtime` npm package. You can use the `-b` flag to bundle the runtime with the generated code:
|
|
|
|
```bash
|
|
wails3 generate bindings -b
|
|
```
|
|
|
|
This will include the runtime code directly in the generated files, eliminating the need for the npm package.
|
|
|
|
### Disabling Index Files
|
|
|
|
If you don't need the index files, you can use the `-noindex` flag to disable their generation:
|
|
|
|
```bash
|
|
wails3 generate bindings -noindex
|
|
```
|
|
|
|
This can be useful if you prefer to import services and models directly from their respective files.
|
|
|
|
## Real-World Examples
|
|
|
|
### Authentication Service
|
|
|
|
Here's an example of an authentication service with custom directives:
|
|
|
|
```go
|
|
package auth
|
|
|
|
//wails:inject console.log("Auth service initialized");
|
|
type AuthService struct {
|
|
// Private fields
|
|
users map[string]User
|
|
}
|
|
|
|
type User struct {
|
|
Username string
|
|
Email string
|
|
Role string
|
|
}
|
|
|
|
type LoginRequest struct {
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
type LoginResponse struct {
|
|
Success bool
|
|
User User
|
|
Token string
|
|
Error string
|
|
}
|
|
|
|
// Login authenticates a user
|
|
func (s *AuthService) Login(req LoginRequest) LoginResponse {
|
|
// Implementation...
|
|
}
|
|
|
|
// GetCurrentUser returns the current user
|
|
func (s *AuthService) GetCurrentUser() User {
|
|
// Implementation...
|
|
}
|
|
|
|
// Internal helper method
|
|
//wails:internal
|
|
func (s *AuthService) validateCredentials(username, password string) bool {
|
|
// Implementation...
|
|
}
|
|
```
|
|
|
|
### Data Processing Service
|
|
|
|
Here's an example of a data processing service with generic types:
|
|
|
|
```go
|
|
package data
|
|
|
|
type ProcessingResult[T any] struct {
|
|
Data T
|
|
Error string
|
|
}
|
|
|
|
type DataService struct {}
|
|
|
|
// Process processes data and returns a result
|
|
func (s *DataService) Process(data string) ProcessingResult[map[string]int] {
|
|
// Implementation...
|
|
}
|
|
|
|
// ProcessBatch processes multiple data items
|
|
func (s *DataService) ProcessBatch(data []string) ProcessingResult[[]map[string]int] {
|
|
// Implementation...
|
|
}
|
|
|
|
// Internal helper method
|
|
//wails:internal
|
|
func (s *DataService) parseData(data string) (map[string]int, error) {
|
|
// Implementation...
|
|
}
|
|
```
|
|
|
|
### Conditional Code Injection
|
|
|
|
Here's an example of conditional code injection for different output formats:
|
|
|
|
```go
|
|
//wails:inject j*:/**
|
|
//wails:inject j*: * @param {string} arg
|
|
//wails:inject j*: * @returns {Promise<void>}
|
|
//wails:inject j*: */
|
|
//wails:inject j*:export async function CustomMethod(arg) {
|
|
//wails:inject t*:export async function CustomMethod(arg: string): Promise<void> {
|
|
//wails:inject await InternalMethod("Hello " + arg + "!");
|
|
//wails:inject }
|
|
type Service struct{}
|
|
```
|
|
|
|
This injects different code for JavaScript and TypeScript outputs, providing appropriate type annotations for each language.
|