---
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.
