Ponte Go-Frontend

Comunicação Direta Go-JavaScript

O Wails fornece uma ponte direta em memória entre Go e JavaScript, permitindo comunicação perfeita sem sobrecarga de HTTP, limites de processo ou gargalos de serialização.

Visão Geral

direction: right

Frontend: "Frontend (JavaScript)" {
  UI: "React/Vue/Vanilla" {
    shape: rectangle
    style.fill: "#8B5CF6"
  }
  
  Bindings: "Auto-Generated Bindings" {
    shape: rectangle
    style.fill: "#A78BFA"
  }
}

Bridge: "Wails Bridge" {
  Encoder: "JSON Encoder" {
    shape: rectangle
    style.fill: "#10B981"
  }
  
  Router: "Method Router" {
    shape: diamond
    style.fill: "#10B981"
  }
  
  Decoder: "JSON Decoder" {
    shape: rectangle
    style.fill: "#10B981"
  }
  
  TypeGen: "Type Generator" {
    shape: rectangle
    style.fill: "#10B981"
  }
}

Backend: "Backend (Go)" {
  Services: "Your Services" {
    shape: rectangle
    style.fill: "#00ADD8"
  }
  
  Registry: "Service Registry" {
    shape: rectangle
    style.fill: "#00ADD8"
  }
}

Frontend.UI -> Frontend.Bindings: "import { Method }"
Frontend.Bindings -> Bridge.Encoder: "Call Method('arg')"
Bridge.Encoder -> Bridge.Router: "Encode to JSON"
Bridge.Router -> Backend.Registry: "Find service"
Backend.Registry -> Backend.Services: "Invoke method"
Backend.Services -> Bridge.Decoder: "Return result"
Bridge.Decoder -> Frontend.Bindings: "Decode to JS"
Frontend.Bindings -> Frontend.UI: "Promise resolves"
Bridge.TypeGen -> Frontend.Bindings: "Generate types"

Insight principal: Sem HTTP, sem IPC, sem limites de processo. Apenas chamadas de função diretas com segurança de tipos.

Como Funciona: Passo a Passo

1. Registro de Serviço (Inicialização)

Quando sua aplicação inicia, o Wails escaneia seus serviços:

type GreetService struct {
    prefix string
}

func (g *GreetService) Greet(name string) string {
    return g.prefix + name + "!"
}

func (g *GreetService) Add(a, b int) int {
    return a + b
}

// Register service
app := application.New(application.Options{
    Services: []application.Service{
        application.NewService(&GreetService{prefix: "Hello, "}),
    },
})

O que o Wails faz:

  1. Escaneia a estrutura em busca de métodos exportados
  2. Extrai informações de tipo (parâmetros, tipos de retorno)
  3. Constrói um registro mapeando nomes de métodos para funções
  4. Gera bindings de TypeScript com definições de tipo completas

2. Geração de Bindings (Tempo de Compilação)

O Wails gera bindings de TypeScript automaticamente:

// Auto-generated: frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function Add(a: number, b: number): Promise<number>

Mapeamento de tipos:

Tipo Go Tipo TypeScript
string string
int, int32, int64 number
float32, float64 number
bool boolean
[]T T[]
map[string]T Record<string, T>
struct interface
time.Time Date
error Exceção (lançada)

3. Chamada no Frontend (Tempo de Execução)

O desenvolvedor chama o método Go do JavaScript:

import { Greet, Add } from './bindings/GreetService'

// Call Go from JavaScript
const greeting = await Greet("World")
console.log(greeting)  // "Hello, World!"

const sum = await Add(5, 3)
console.log(sum)  // 8

O que acontece:

  1. Função de binding chamada - Greet("World")
  2. Mensagem criada - { service: "GreetService", method: "Greet", args: ["World"] }
  3. Enviada para a ponte - Via ponte JavaScript do WebView
  4. Promise retornada - Aguarda resposta

4. Processamento da Ponte (Tempo de Execução)

A ponte recebe a mensagem e a processa:

direction: down

Receive: "Receive Message" {
  shape: rectangle
  style.fill: "#10B981"
}

Parse: "Parse JSON" {
  shape: rectangle
}

Validate: "Validate" {
  Check: "Service exists?" {
    shape: diamond
  }
  
  CheckMethod: "Method exists?" {
    shape: diamond
  }
  
  CheckTypes: "Types correct?" {
    shape: diamond
  }
}

Invoke: "Invoke Go Method" {
  shape: rectangle
  style.fill: "#00ADD8"
}

Encode: "Encode Result" {
  shape: rectangle
}

Send: "Send Response" {
  shape: rectangle
  style.fill: "#10B981"
}

Error: "Send Error" {
  shape: rectangle
  style.fill: "#EF4444"
}

Receive -> Parse
Parse -> Validate.Check
Validate.Check -> Validate.CheckMethod: "Yes"
Validate.Check -> Error: "No"
Validate.CheckMethod -> Validate.CheckTypes: "Yes"
Validate.CheckMethod -> Error: "No"
Validate.CheckTypes -> Invoke: "Yes"
Validate.CheckTypes -> Error: "No"
Invoke -> Encode: "Success"
Invoke -> Error: "Error"
Encode -> Send

Segurança: Apenas serviços registrados e métodos exportados são chamáveis.

5. Execução Go (Tempo de Execução)

O método Go é executado:

func (g *GreetService) Greet(name string) string {
    // This runs in Go
    return g.prefix + name + "!"
}

Contexto de execução:

  • Executa em uma goroutine (não bloqueante)
  • Tem acesso a todos os recursos do Go (sistema de arquivos, rede, bancos de dados)
  • Pode chamar outro código Go livremente
  • Retorna resultado ou erro

6. Resposta (Tempo de Execução)

O resultado é enviado de volta ao JavaScript:

// Promise resolves with result
const greeting = await Greet("World")
// greeting = "Hello, World!"

Tratamento de erros:

func (g *GreetService) Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}
try {
    const result = await Divide(10, 0)
} catch (error) {
    console.error("Go error:", error)  // "division by zero"
}

Características de Desempenho

Velocidade

Sobrecarga típica de chamada: <1ms

Frontend Call → Bridge → Go Execution → Bridge → Frontend Response
     ↓            ↓           ↓            ↓            ↓
   &lt;0.1ms      &lt;0.1ms      [varies]     &lt;0.1ms      &lt;0.1ms

Comparado a alternativas:

  • HTTP/REST: 5-50ms (stack de rede, serialização)
  • IPC: 1-10ms (limites de processo, marshalling)
  • Wails Bridge: <1ms (em memória, chamada direta)

Memória

Sobrecarga por chamada: ~1KB (buffer de mensagem)

Otimização zero-copy: Dados grandes (>1MB) usam memória compartilhada quando possível.

Concorrência

Chamadas são concorrentes:

  • Cada chamada executa em sua própria goroutine
  • Múltiplas chamadas podem executar simultaneamente
  • Sem bloqueio entre chamadas
// These run concurrently
const [result1, result2, result3] = await Promise.all([
    SlowOperation1(),
    SlowOperation2(),
    SlowOperation3(),
])

Sistema de Tipos

Tipos Suportados

Primitivos

// Go
func Example(
    s string,
    i int,
    f float64,
    b bool,
) (string, int, float64, bool) {
    return s, i, f, b
}
// TypeScript (auto-generated)
function Example(
    s: string,
    i: number,
    f: number,
    b: boolean,
): Promise<[string, number, number, boolean]>

Fatias e Arrays

// Go
func Sum(numbers []int) int {
    total := 0
    for _, n := range numbers {
        total += n
    }
    return total
}
// TypeScript
function Sum(numbers: number[]): Promise<number>

// Usage
const total = await Sum([1, 2, 3, 4, 5])  // 15

Mapas

// Go
func GetConfig() map[string]interface{} {
    return map[string]interface{}{
        "theme": "dark",
        "fontSize": 14,
        "enabled": true,
    }
}
// TypeScript
function GetConfig(): Promise<Record<string, any>>

// Usage
const config = await GetConfig()
console.log(config.theme)  // "dark"

Estruturas

// Go
type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func GetUser(id int) (*User, error) {
    return &User{
        ID:    id,
        Name:  "Alice",---

**Dúvidas sobre a ponte?** Pergunte no [Discord](https://discord.gg/JDdSxwjhGf) ou verifique os [exemplos de binding](https://github.com/wailsapp/wails/tree/master/v3/examples/binding).
Edit page

Last updated: