Как стать автором
Обновить
46.95
Tuna
Dev-Team-Sec-Ops, сервисы для разработчиков

Десктопное кросс-платформенное приложение на Wails (Golang + Vue.js). Как мы делали Tuna Desktop

Уровень сложностиПростой
Время на прочтение9 мин
Количество просмотров4K

Что такое Wails?

Wails - это легковесный фреймворк, предназначенный для создания кросс-платформенных GUI приложений рабочего стола на golang и стандартных веб технологиях (Svelte, React, Preact, Vue, Lit, Vanilla JS). Ближайшие аналоги это естественно Electron (JS), Tauri (Rust), хочется добавить Qt (С++), но это уже другой уровень. Сразу скажу, что Wails не идеален, имеет множество ограничений и в целом не подойдёт для чего-то крупного, Tauri к примеру более зрелый проект, больше функций, быстрее развивается, больше и живее сообщество, но это уже на rust, а это не наш стэк.

Ключевое отличие Wails и Tauri от Electron, в том, что последний таскает с собой chromium, тогда как Wails и Tauri используют встроенный в систему нативный браузер. В Windows - движок Edge, Webview2 (по сути chromium). В macOS - это движок Safari, WebKit. В Linux - WebKitGTK. Исходя из этого есть ограничения, к примеру поддерживается только Windows 10+, а в Linux вы устанете на этапе сборки и дистрибуции, так как зоопарк дистрибутивов и библиотеки с зависимостями (webkitgtk2) везде называются по разному.

Но у нас не было требований к какой-то огромной функциональности, почти всё базовое есть в текущей версии, не хватает пожалуй поддержки трея, нотификаций и открытия дочерних окон, но для первой версии мы решили, что это не критично. Да и вроде как медленно но верно развивается 3я версия фреймворка где функций станет больше и всё это появится!

И да, мы говорим о Wails v2.

Инициализация проекта

Чтобы вы понимали насколько легко начать, я покажу:

  • Устанавливаем Wails:
    go install github.com/wailsapp/wails/v2/cmd/wails@latest

  • Устанавливаем node.js:
    nvm install --lts
    nvm use --lts

  • Запустите wails doctor , он просканирует систему и подскажет что ещё установить:

Пример вывода wails doctor
$ wails doctor                                                                                                                                                          

                                
          Wails Doctor          
                                

                                                                                                                                                                         
# Wails
Version         | v2.10.1
Package Manager | zypper 


# System
WARNING: failed to read int from file: open /sys/devices/system/cpu/cpu0/online: no such file or directory
┌───────────────────────────────────────────────────────────────────────────────────────┐
| OS           | openSUSE Tumbleweed                                                    |
| Version      | 20250531                                                               |
| ID           | opensuse-tumbleweed                                                    |
| Go Version   | go1.23.8                                                               |
| Platform     | linux                                                                  |
| Architecture | amd64                                                                  |
| CPU          | 12th Gen Intel(R) Core(TM) i7-1260P                                    |
| GPU 1        | TU117GLM [T550 Laptop GPU] (NVIDIA Corporation) - Driver: nvidia       |
| GPU 2        | Alder Lake-P GT2 [Iris Xe Graphics] (Intel Corporation) - Driver: i915 |
| Memory       | 47GB                                                                   |
└───────────────────────────────────────────────────────────────────────────────────────┘

# Dependencies
┌───────────────────────────────────────────────────────────────────┐
| Dependency | Package Name            | Status    | Version        |
| *docker    | docker                  | Installed | 28.2.2_ce-17.1 |
| gcc        | gcc-c++                 | Installed | 14-3.1         |
| libgtk-3   | gtk3-devel              | Installed | 3.24.49+14-1.1 |
| libwebkit  | webkit2gtk3-soup2-devel | Available | 2.48.3-1.1     |
| npm        | Unknown                 | Not Found | 10.9.2         |
| pkg-config | pkgconf-pkg-config      | Installed | 2.2.0-1.3      |
|                                                                   |
└───────────────────── * - Optional Dependency ─────────────────────┘

# Diagnosis
Required package(s) installation details: 
  - libwebkit: sudo zypper in webkit2gtk3-soup2-devel

 WARNING  Your system has missing dependencies!
Fatal:
Required dependencies missing: npm
Please read this article on how to resolve this: https://wails.io/guides/resolving-missing-packages

 ♥   If Wails is useful to you or your company, please consider sponsoring the project:
https://github.com/sponsors/leaanthony
  • Инициализируйте проект:

$ wails init -n desktop -t vue                                           
Wails CLI v2.10.1


# Initialising Project 'desktop'
Project Name      | desktop                    
Project Directory | /tmp/tmp.hX2eO7pGKq/desktop
Template          | Vue + Vite                 
Template Source   | https://wails.io           


Initialised project 'desktop' in 53ms.

 ♥   If Wails is useful to you or your company, please consider sponsoring the project:
https://github.com/sponsors/leaanthony
  • Запустите проект в DEV режиме wails dev

Запуск wails dev
Запуск wails dev

Структура проекта будет выглядеть примерно так:

$ tree -L 2 .                                                                                                                                                           
.
├── app.go
├── build
│   ├── appicon.png
│   ├── bin
│   ├── darwin
│   ├── README.md
│   └── windows
├── frontend
│   ├── dist
│   ├── index.html
│   ├── node_modules
│   ├── package.json
│   ├── package.json.md5
│   ├── package-lock.json
│   ├── README.md
│   ├── src
│   ├── vite.config.js
│   └── wailsjs
├── go.mod
├── go.sum
├── main.go
├── README.md
└── wails.json

В корне у вас есть файл wails.json, в нём информация о проекте, многое придётся переопределить для дистрибуции, имена и прочее. В каталоге frontend - как ни странно UI часть приложения. В каталоге build OS специфичные файлы нужные для последующей сборки артефактов и дистрибуции, тут же иконка и так далее. Я не хочу расписывать всё подробно, так как всё это есть в документации и issues на GH.

Архитектура и разработка

После запуска wails dev, у вас откроется окно приложения, с заданными параметрами из main.go, а интерфейс вы разрабатываете в каталоге frontend. Но кажется нужно немного пояснить, у вас не будет привычного REST API, вместо этого будет RPC взаимодействие между фронтендом (JavaScript/TypeScript) и бэкендом (Go). Это позволяет фронтенду вызывать методы, которые реализованы на Go, так, будто они локальные JavaScript-функции.

Более подробно про то, как это работает можно почитать тут. Так что если сразу уложить это в голове, то всё становится просто.

Tuna Desktop

Перейдём к нашему приложению. Основной наш продукт - это реверс прокси туннели из интернета в локальную сеть, т.е. аналог Ngrok. И да у нас есть консольный клиент - tuna, и так как мы сами активно пользуемся своим продуктом, в какой-то момент мы подумали - Было бы классно сделать десктопное приложение!

🤷‍♂️ Зачем?

При локальной разработке часто бывает так, что есть какой-то туннель с статичным адресом, который должен быть доступен всегда. Например, когда мы тестируем наши платежи в ЮКасса, у нас есть тестовый магазин для каждого разработчика, где прописан статический адрес HTTP уведомления. Открывать каждый раз отдельный терминал и писать tuna http -l ru -s test-yookassa-1 8080 становится утомительно, я каждый раз забываю сделать это заранее и приходится создавать несколько счетов или ждать когда платёжная система отправит повторное уведомление.

Также мы знаем, что порой открыть доступ к локальному ресурсу нужно не только разработчикам или системным администраторам, а командная строка не самый дружелюбный интерфейс.

Сложив несколько факторов мы решили сделать GUI приложение с максимально простым интерфейсом, чтобы пользоваться было комфортно даже бухгалтерке.

🎯 Ключевые возможности​

Исходя из требований - приложение должно быть супер простым, а также ограничение самого фреймворка, сейчас на момент первого релиза, приложение имеет минимум возможностей:

При этом даже этот функционал сильно ограничен относительно консольной версии. В будущем мы всё таки планируем расширить функционал, к примеру добавить файловый сервер и базовую авторизацию.

🧑‍💻 Поддерживаемые платформы

У нас примерно равное количество клиентов на всех OS, поэтому вопрос о кроссплатформенности не стоял, это было обязательное требование. Так, что сегодня вы можете установить наше десктопное приложение на любой современной ОС.

🤔 Так почему мы всё таки выбрали Wails?

Действительно, если есть пробелы в функционале, то почему мы просто не взяли Tauri или проверенный годами Electron или QT?

Главный аргумент - Wails это наш стэк! 🐘💪

Проект уже полностью написан на Go, есть полноценный консольный клиент и мы можем на основе единой кодовой базы использовать один и тот же конструктор. Именно поэтому мы смогли всё сделать так быстро ну и как нам кажется качественно. В случае Electron - пришлось бы тянуть клиент tuna cli и запускать туннели с помощью exec, следить, что они не упали, синхронизировать всё это. С Tauri скорее всего пришлось бы заново написать логику клиента на Rust, а с QT на C++, ну такое 😁.

Ну и Tuna Desktop - это не Slack или Spotify, мы преследовали другие цели.

Когда мы начали разрабатывать приложение, мы хотели не просто завернуть наш личный кабинет в обёртку WebView. Мы отказались от этого самого простого и часто используемого пути, по которому идут многие десктопные приложения.

Нам хотелось создать новый пользовательский опыт — особенно для тех, кому неудобно работать с консолью. Есть пользователи, которым просто неприятно взаимодействовать с терминалом, кому-то не нравится формат CLI, а кто-то просто предпочитает привычный интерфейс с кнопками и понятной навигацией. Мы хотели, чтобы у этих людей был выбор — пользоваться десктопным, нативным на вид приложением.

Конечно, по сути мы использовали те же самые компоненты, которые уже были реализованы в личном кабинете и клиенте: тот же UI, та же GOшная кодовая база. Но мы подошли к дизайну по-другому, чтобы это действительно ощущалось как самостоятельное приложение, а не просто оболочка вокруг веба.

В результате за буквально один-два дня мы собрали рабочий прототип. Это было быстро и просто, потому что мы использовали уже готовые элементы — нам не пришлось тратить время на долгие исследования или продумывать всё с нуля. Мы сразу сделали то, что можно было бы уже распространять.

Сложности при сборке и дистрибуции

Если вы вдруг подумали, что всё так просто и радужно, то - НЕТ!

Выше я упомянул, что приложение было готово за 1-2 дня, так вот на сборку и настройку дистрибуции ушло около 3-х недель 🤯.

Во первых так как есть глубокие интеграции с OS - это зависимость от CGO, а так как проект кросс-платформенный - добро пожаловать в мир кросс-компиляции c CGO в golang. Но я сэкономлю вам неделю исследований и скажу так - вы не сможете собрать проект из Linux для macOS 🤷‍♂️. Вот тут я описал проблематику, если коротко, то в macOS SDK есть заглушки которые не позволят вам собрать GUI приложение не на Mac. Всё сломается на этапе линковки и не важно что у вас там zig или osxcross, ограничение именно SDK. Поэтому для сборки под macOS вам нужен Mac! Мы поставили gitlab-runner на наш macmini и теперь собираем на нём, но были варианты и с всякими хостингами, так что не тупиковая ситуация.

Кстати у нас есть проект для сборки golang образа с всем нужным тулкитом для кросс-компиляции под разные OS и архитектуры, пользуйтесь.

Во вторых, сборка под Linux...
Ну начнём с того, что есть разные версии библиотек webkit2gtk-4.0 и webkit2gtk-4.1. И например в Ubuntu 24.04 есть уже только последняя и собирать надо с флагом -tags webkit2_41, а в RHEL 9 (и все клоны) есть только webkit2gtk-4.0, в SUSE, Fedora и ArchLinux есть обе версии. И получается уже на этапе сборки у вас будет 2 артефакта. Но было бы слишком просто если бы этим всё ограничилось. Собрать весь нужный тулкит с нужным окружением и версиями для компиляции под linux arm64 + webkit2gtk-4.1 оказалось дольше и сложнее, чем арендовать linux arm64 сервер и запустить там gitlab-runner, так что мы пошли по простому пути и для Linux arm64 тоже собираем нативно, как и под macOS 🙃.

Далее я думал, что смогу собрать AppImage, но там тоже возникли сложности, потратив несколько дней я понял, что проще собрать классические deb/rpm пакеты и указать зависимости. Опять же, чтобы вы не страдали, я поработал за вас и составил вот такую табличку:

Таблица зависимостей для Wails / WebKitGTK-приложения

Зависимости для сборки под разные дистрибутивы:

Дистрибутив

GTK3

WebKit2GTK

ABI

Пример установки

Debian 12 / Ubuntu 22.04 (и старше)

libgtk-3-0

libwebkit2gtk-4.1-0

4.1

apt install libgtk-3-0 libwebkit2gtk-4.1-0

Debian 11 / Ubuntu 20.04 (и младше)

libgtk-3-0

libwebkit2gtk-4.0-37

4.0

apt install libgtk-3-0 libwebkit2gtk-4.0-37

openSUSE Leap / Tumbleweed

libgtk-3-0

libwebkit2gtk-4_1-0

4.1

zypper install libgtk-3-0 libwebkit2gtk-4_1-0

RHEL / CentOS / AlmaLinux / Rocky (до 9)

gtk3

webkit2gtk3

4.0

dnf install gtk3 webkit2gtk3

Fedora 40+

gtk3

webkit2gtk4.1

4.1

dnf install gtk3 webkit2gtk4.1

Arch Linux / Manjaro

gtk3

webkit2gtk-4.1

4.1

pacman -S gtk3 webkit2gtk-4.1

Примечания:

  • В openSUSE Leap доступны обе версии WebKitGTK (4.0 и 4.1), но мы берём libwebkit2gtk-4_1-0

  • В Fedora до версии 39 включительно был только webkit2gtk4.0, начиная с Fedora 40 появился webkit2gtk4.1.

  • В RHEL/Alma/Rocky/CentOS (8 и 9) webkit2gtk3 — это 4.0 ABI, 4.1 пока нет.

  • В Arch есть оба пакета (webkit2gtk и webkit2gtk-4.1), но для нового ABI используем второй.

Получается с флагом -tags webkit2_40 собираем только для RHEL, остальные уже имеют современную версию и для них -tags webkit2_41.

Эта таблица максимально отражает современное состояние репозиториев и пакетов (на май 2025 года).

Как итог теперь у нас есть 3 разных rpm пакета 1 deb и 1 pacman, все под amd64 и arm64.

Удивительно, но меньше всего проблем оказалось при сборке для Windows, но мы пока не стали собирать для arm64, так как в репозиториях debian нет готового тулкита Mingw-w64 для этой архитектуры, а я устал ещё на этапе с Linux 😄. К слову в Wails есть поддержка NSIS инсталлятора из коробки, так что и тут всё решено и вашему приложению не обязательно быть portable.

Публикация в Store

Мы находимся здесь 😉

Для Linux все обновления автоматические через репозиторий, не зря мы всё таки решили собирать стандартные пакеты. А вот для macOS мы пока пакуем DMG и распространяем через сайт, в Windows таже ситуация но с EXE установщиком. И получается ни там ни там, нет нормальной системы доставки. Поэтому сейчас мы на этапе публикации приложения в официальные магазины Apple App Store и Microsoft Windows Store. Так, что если вам интересен этот опыт, то напишите об этом в комментариях и позже я постараюсь подготовить статью об этом опыте.

Итоги

Мы однозначно довольны выбором Wails, конечно, если бы изначально были реализованы такие вещи, как трей, уведомления и дочерние окна, это был бы почти идеальный проект — слишком хороший, чтобы быть доступным просто так и бесплатно. Но мы потратили не так много ресурсов, а наши пользователи остались довольны.

Если вы хотите начать делать своё GUI приложение подойдите к выбору основательно, не забывайте про правило 20/80 и не бойтесь чем то жертвовать. Лучше НЕ идеальное приложение сегодня, чем идеальное никогда.


На этом у меня всё, спасибо что дочитали до конца 🙂

Если вы мечтали о десктопной версии аналога Ngrok, то - используйте Tuna Desktop.

Тут я хочу напомнить, что Tuna - это платформа для разработчиков и их команд, нацеленная на ускорение разработки, упрощение командного взаимодействия и безопасность.

Контакты

Если возникли вопросы, можете задать их нам по почте info@tuna.am, тут в коментариях или нашем чате в telegram.

Теги:
Хабы:
+12
Комментарии31

Публикации

Информация

Сайт
tuna.am
Дата регистрации
Дата основания
Численность
2–10 человек