Доброго времени суток, уважаемые пользователи Хабра.
Я не то что бы профессиональный разработчик на C++, в основном я занимаюсь геймдевом на UE5 (по крайней мере последнее время). Но последнее время достаточно часто я балуюсь разработкой десктоп приложений под Windows. Для красоты и простоты я задумывался об использовании именно react. Но из выбора что я увидел было 2 варианта:
Tauri - Фреймворк под Rust с отрисовкой фронтенда сделанном на React и т.п.
Electron - фреймворк для разработки кроссплатформенных настольных приложений с использованием веб-технологий (скопировал описание с гугла)
Electron я отмел сразу, так как хотел писать бэкенд на чем то более удобном чем JS/TS для себя. Tauri мне очень понравился, но изучение Rust заняло немного времени. И смотря на это все я подумал, что можно реализовать какой-нибудь аналог Tauri используя C++.
Немного посидев поизучав информацию, я примерно выстроил себе план работы, из этого вылился первый MVP Shine. Фреймворк на данный момент поддерживает только Windows и тесно связан с vcpkg, так как находится на очень ранней стадии разработки, но его уже вполне себе можно потыкать и использовать.
А теперь к установке и использовании:
Для начала то, что нам нужно для запуска:
CMake
Node.JS
CLion (можете использовать что-то своё, мне комфортнее в нём)
Дальше мы открываем терминал и прописываем команду:npm create shine-app@latest
У нас появится простая на данный момент настройка проекта, а именно указание его имени:

Дальше после того как мы введём имя приложение он создаст папку со всем, что нам нужно для реализации приложения

Структура проекта у нас выглядит следующим образом:
D:. ├───cmake # кастомные cmake функции для удобства сборки и запуска ├───frontend # Тут у нас находится фронтенд, сам UI приложения │ ├───public │ └───src │ └───assets ├───generated # Тут у нас лежат ассеты собранные в бинарник, чтобы не таскать их за собой в релизе ├───scripts # Скрипты сборки для удобства ├───shine # Код библиотеки │ ├───components │ │ ├───include │ │ │ └───shine │ │ │ └───components │ │ └───src │ └───core │ ├───include │ │ └───shine │ │ └───engine │ └───src │ └───engine │ └───win32 └───src # Код нашего приложения (в данном случае main.cpp)
На данный момент я не придумал ничего лучше, чем тянуть за собой код библиотеки в пример, чтобы избежать бед со сборкой с разными компиляторами
Дальше мы открываем проект в CLion (или там где удобно вам) и настраиваем профили CMake, У меня это выглядит так:

Дальше идем в View -> Tool Windows -> vcpkg

Далее выбираем наш существующий манифест, и нажимаем на карандашик сверху чтобы он работал с нашими CMake профилями:

Кликаем галочку Add vcpkg integration to existing CMake profiles

Далее кликаем ПКМ по корневому CMakeLists.txt и нажимаем Reload CMake Project.

Дальше мы можем спокойно запустить приложение и увидеть что оно работает:

Идею темплейта я решил взять просто с Tauri, простое окно где можно ввести имя и при нажатии Greet наше C++ ядро отформатирует сообщение и выведет его во фронтенде:

Со стороны C++ наш handler функции greet выглядит следующим образом:
SHINE_COMMAND(greet) { // У функции собранной с SHINE_COMMAND по дефолту есть аргументы // В развернутом виде функция выглядит примерно так: // nlohmann::json greet(const nlohmann::json& args) std::string name_str = args["name"]; return std::format("Hello, {}", name_str); }
и указание того, что мы можем вызвать эту функцию из фронтенда:
app.GetRouter().AddHandlers({SHINE_HANDLER(greet)});
После этого наш фронтенд знает что мы можем вызывать функцию greet с помощью метода invoke. Выглядит это следующим образом:
async function handleGreet() { if (!name.trim()) return; setIsLoading(true); try { // Вызываем функцию и записываем ответ в setGreetMsg const res = await invoke('greet', { name }); setGreetMsg(res.result || res); } catch (error) { setGreetMsg("Error: Could not connect to Shine Core"); } finally { setIsLoading(false); } }
Дальше мы можем как угодно переделывать наш проект React и делать наше UI. При сборке в дебаге приложение просто слушает локалхост с нашим портом, в Shine есть поддержка HMR и при изменении кода, UI в приложении так же изменится. При релизе же, проект фронтенда собирается и после чего переводятся в байты, дальше мы используем эти байты внутри приложения не распаковывая их храним в памяти.
Помимо всего этого у нас есть конфиг файл: shine.conf.json, выглядит он так по стандарту:
{ "window": { "title": "Shine Secure App", "width": 900, "height": 600 }, "capabilities": { "allowedCommands": [ "fs_read_text_file", "window_drag" ] } }
В нем пока что мы указываем title окна приложения, его размеры. Помимо этого есть ещё 2 параметра конфига:
frameless - Отключает рамки у окна
resizable - Разрешает / запрещает изменение размера окна
При дебаге конфиг будет подтягиваться из файла, при сборке он так же находится в итоговом приложении, опять же чтобы не тянуть за собой лишние файлы.
Учитывая что мы пишем на C++, и запихиваем ассеты фронтенда прямиком в бинарник, приложение из template имеет достаточно приятный вес - всего 845кб, при этом он не требует зависимостей для запуска и можно отправлять голый .exe пользователю и он запустится на его системе.

В планах у меня реализовать поддержку Linux и MacOS, а так же возможность получать состояние элементов фронтенда из плюсов и взаимодействия с ними. Например заполнять прогресс бар условный из C++ при какой-нибудь загрузке и т.п.
Это моя первая попытка сделать что-либо полезное на C++ для опенсорса, буду очень рад объективной критике, советам и контрибьютингу.