--- 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` 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 { "Data": T; "Error": string; constructor(source: Partial> = {}) { if (!("Data" in source)) { this["Data"] = null as any; } if (!("Error" in source)) { this["Error"] = ""; } Object.assign(this, source); } static createFrom(source: string | object = {}): Result { let parsedSource = typeof source === "string" ? JSON.parse(source) : source; return new Result(parsedSource as Partial>); } } ``` ### 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; 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} //wails:inject j*: */ //wails:inject j*:export async function CustomMethod(arg) { //wails:inject t*:export async function CustomMethod(arg: string): Promise { //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.