Как работает Wails
Архитектура Wails и способы достижения производительности нативных приложений
Wails — это фреймворк для создания настольных приложений, использующий Go для бэкенда и веб-технологии для фронтенда. Но, в отличие от Electron, Wails не включает браузер в комплект поставки, а использует нативный WebView операционной системы.
Основные отличия от Electron:
| Аспект | Wails | Electron |
|---|---|---|
| Браузер | WebView, предоставляемый ОС | Chromium в комплекте поставки (~100 МБ) |
| Бэкенд | Go (компилируемый) | Node.js (интерпретируемый) |
| Взаимодействие | Мост в памяти | IPC (межпроцессное взаимодействие) |
| Размер пакета | ~15 МБ | ~150 МБ |
| Память | ~10 МБ | ~100 МБ+ |
| Запуск | <0.5 с | 2-3 с |
Основные компоненты
1. Нативный WebView
Wails использует встроенный в операционную систему движок веб-рендеринга:
WebView2 (Microsoft Edge WebView2)
- Основан на Chromium (как и браузер Edge)
- Предустановлен в Windows 10/11
- Автоматически обновляется через Windows Update
- Полностью поддерживает современные веб-стандарты
WebKit (движок рендеринга Safari)
- Встроен в macOS
- Тот же движок, что и в браузере Safari
- Отличная производительность и длительное время работы от аккумулятора
- Полностью поддерживает современные веб-стандарты
WebKitGTK (порт WebKit для GTK)
- Устанавливается через менеджер пакетов
- Тот же движок, что и в GNOME Web (Epiphany)
- Хорошая поддержка стандартов
- Низкое потребление ресурсов и высокая производительность
Почему это важно:
- Нет браузера в комплекте поставки → Меньший размер приложения
- Нативность для ОС → Лучшая интеграция и производительность
- Автоматические обновления → Исправления безопасности поступают с обновлениями ОС
- Привычный рендеринг → Такой же, как в системном браузере
2. Мост Wails
Мост — это сердце Wails: он обеспечивает прямое взаимодействие между Go и JavaScript.
Как это работает:
- Фронтенд вызывает метод Go (через автоматически сгенерированную привязку)
- Мост кодирует вызов в JSON (имя метода + аргументы)
- Маршрутизатор находит метод Go в зарегистрированных сервисах
- Метод Go выполняется и возвращает значение
- Мост декодирует результат и отправляет его обратно во фронтенд
- Promise завершается в JavaScript с полученным результатом
Характеристики производительности:
- В памяти: без сетевых накладных расходов и без HTTP
- Без копирования там, где это возможно (для больших объёмов данных)
- Асинхронность по умолчанию: обе стороны работают без блокировки
- Типобезопасность: определения TypeScript создаются автоматически
3. Система сервисов
Сервисы — рекомендуемый способ предоставления фронтенду функций Go.
// Define a service (just a regular Go struct)
type GreetService struct {
prefix string
}
// Methods with exported names are automatically available
func (g *GreetService) Greet(name string) string {
return g.prefix + name + "!"
}
func (g *GreetService) GetTime() time.Time {
return time.Now()
}
// Register the service
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&GreetService{prefix: "Hello, "}),
},
})Обнаружение сервисов:
- При запуске Wails сканирует вашу структуру
- Экспортируемые методы становятся доступными для вызова из фронтенда
- Информация о типах извлекается для привязок TypeScript
- Обработка ошибок выполняется автоматически (ошибки Go → исключения JS)
Сгенерированная привязка TypeScript:
// Auto-generated in frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function GetTime(): Promise<Date>Зачем нужны сервисы?
- Типобезопасность: полная поддержка TypeScript
- Автоматическое обнаружение: регистрировать методы вручную не требуется
- Упорядоченность: связанная функциональность сгруппирована
- Удобство тестирования: сервисы представляют собой обычные структуры Go
4. Система событий
События обеспечивают обмен данными по модели «издатель — подписчик» между компонентами.
Варианты использования:
- Обмен данными между окнами: одно окно уведомляет другие
- Фоновые задачи: сервис Go сообщает пользовательскому интерфейсу о ходе выполнения
- Синхронизация состояния: состояния нескольких окон синхронизируются
- Слабая связанность: компонентам не нужны прямые ссылки друг на друга
Пример:
// Go: Emit an event
app.Event.Emit("user-logged-in", user)// JavaScript: Listen for event
import { Events } from '@wailsio/runtime'
Events.On('user-logged-in', (user) => {
console.log('User logged in:', user)
})Жизненный цикл приложения
Понимание жизненного цикла помогает определить, когда инициализировать ресурсы и освобождать их.
Обработчики жизненного цикла:
app := application.New(application.Options{
Name: "My App",
// Cleanly intercept quit requests (e.g. unsaved changes).
ShouldQuit: func() bool { return true },
// Called when the app is confirmed to be quitting — save state, close connections, etc.
OnShutdown: func() {},
})У application.Options нет поля OnStartup. Действия при запуске следует выполнять в ServiceStartup(ctx, options) сервиса, в обратном вызове, зарегистрированном с помощью app.Event.OnApplicationEvent(events.Common.ApplicationStarted, ...), или просто перед app.Run().
Процесс сборки
Рассмотрим, как Wails собирает приложение:
Этапы сборки:
- Анализ кода Go
- Поиск экспортируемых методов в сервисах
- Извлечение типов параметров и возвращаемых значений
- Создание сигнатур методов
- Создание привязок TypeScript
- Создание файлов
.tsдля каждого сервиса - Добавление полных определений типов
- Добавление комментариев JSDoc
- Сборка фронтенда
- Запуск сборщика (Vite, webpack и т. п.)
- Минификация и оптимизация
- Вывод в
frontend/dist/
- Компиляция Go
- Компиляция с оптимизациями (
-ldflags="-s -w") - Добавление метаданных сборки
- Компиляция для целевой платформы
- Встраивание ресурсов
- Встраивание файлов фронтенда в исполняемый файл Go
- Сжатие ресурсов
- Создание единого исполняемого файла
Результат: единый нативный исполняемый файл со всеми встроенными ресурсами.
Разработка и эксплуатация
В режимах разработки и эксплуатации Wails работает по-разному:
Характеристики:
- Горячая перезагрузка: изменения во фронтенде применяются мгновенно
- Карты исходного кода: отладка с использованием исходного кода
- DevTools: доступны инструменты разработчика браузера
- Журналирование: включено подробное журналирование
- Внешний фронтенд: обслуживается сервером разработки (Vite)
Как это работает:
Преимущества:
- Мгновенная обратная связь при внесении изменений
- Полные возможности отладки
- Более быстрые итерации разработки
Характеристики:
- Встроенные ресурсы: фронтенд включён в исполняемый файл
- Оптимизация: минификация и сжатие
- Без DevTools: по умолчанию отключены
- Минимальное журналирование: регистрируются только ошибки
- Один файл: всё содержится в одном исполняемом файле
Как это работает:
Преимущества:
- Распространение в виде одного файла
- Меньший размер (благодаря минификации)
- Более высокая производительность
- Нет внешних зависимостей
Модель памяти
Понимание использования памяти помогает создавать эффективные приложения.
Области памяти:
- Куча Go
- Ваши сервисы и состояние приложения
- Управляется сборщиком мусора Go
- Обычно 5-10 МБ для простых приложений
- Память WebView
- DOM, куча JavaScript, CSS
- Управляется движком WebView
- Обычно 10-20 МБ для простых приложений
- Память моста
- Буферы сообщений для обмена данными
- Минимальные накладные расходы (<1 МБ)
- По возможности передача больших объёмов данных без копирования
Советы по оптимизации:
- Избегайте передачи больших объёмов данных: передавайте идентификаторы, а подробные данные загружайте по запросу
- Используйте события для обновлений: не выполняйте опрос из фронтенда
- Передавайте большие файлы потоково: не загружайте их в память целиком
- Удаляйте ненужные обработчики: удаляйте обработчики событий, когда они больше не нужны
Подробнее о производительности →
Модель безопасности
Архитектура Wails безопасна по умолчанию:
Механизмы безопасности:
- Белый список методов
- Можно вызывать только экспортируемые методы
- Закрытые методы недоступны
- Требуется явная регистрация сервисов
- Проверка типов
- Аргументы проверяются на соответствие типам Go
- Значения недопустимых типов отклоняются
- Предотвращает атаки с внедрением кода
- Без eval()
- Фронтенд не может выполнять произвольный код Go
- Можно вызывать только предопределённые методы
- Нет динамического выполнения кода
- Изоляция контекста
- У каждого окна есть собственный контекст
- Сервисы могут проверять контекст вызывающей стороны
- Для каждого окна можно задать отдельные разрешения
Рекомендации:
- Проверяйте пользовательский ввод в Go (не доверяйте фронтенду)
- Используйте контекст для аутентификации и авторизации
- Очищайте пути к файлам перед операциями с файлами
- Ограничивайте частоту ресурсоёмких операций
Следующие шаги
Жизненный цикл приложения — изучите запуск, завершение работы и перехватчики жизненного цикла Подробнее →
Мост между Go и фронтендом — подробно изучите работу моста Подробнее →
Система сборки — узнайте, как Wails собирает ваше приложение Подробнее →
Приступайте к разработке — примените полученные знания на практике в учебном руководстве Учебные руководства →
Есть вопросы об архитектуре? Задайте их в Discord или обратитесь к справочнику по API.