Попробуйте Tauri
- воскресенье, 13 октября 2024 г. в 00:00:18
Хочу рассказать про один из моих любимых Opensource проектов: Tauri. Это среда для создания десктопно-мобильных приложений на JavaScript, но быстрых и легковесных. С опциональными дополнениями на Rust, а через него и на всех других языках.
Поддерживается Линь, Вынь и Дрюнь и всякое Ябло. EXEшник HelloWorld весит 1 мегабайт ( ну 5, если не ужиматься в угол как сирота в барском доме ). В памяти занимает на Win 11 200 Мб. (Из них >90% приходится на системные компоненты, расшаренные с другими программами. Поэтому простые средства измерения покажут 5 Мб). Кто-то считает, что это много. Покажите меньше. Только HelloWorld у нас будет такой: в верхней половине окна играет видео с вэба со звуком, а под ним кнопка закрыть, которая при наведении мыши начинает вращаться, и оба эти компонента рендерятся на GPU.
Это достигается тем, что Tauri не тащит с собой браузер, а использует тот, что уже есть в системе. И в самом деле, зачем? В Windows всегда есть движок от Edge, даже если в говносборке вырезан сам Edge. В Андроиде и Ябле всегда есть есть WebKit. Ну а линуксоидов зависимостями не напугаешь, там требуется пакет GTK-WebView. Поддерживается даже Win7/8, но там нужен пакет совместимости весом ~200Мб. Таким образом получается, что нам встретится всего два движка - Хром и WebKit, и на дворе 2024 год, поэтому разница между ними не такая уж значительная.
Вторая приятная сторона Tauri - это гибкость. Полнофункциональное GUI приложение на нём можно написать как целиком на Rust, без строчки на JS, так и целиком на JS, c ровно одной строчкой на Rust. Поэтому знать Rust для его использования не обязательно совсем. Tauri предоставляет в пространство JS модули API для операций, недоступных из браузера - вроде прямого доступа к файлам и железу.
Зрада! Возможность работать только на JS появилась в Tauri 2, который вышел около года назад. Поэтому в сети до сих пор много ссылок на документацию первой версии, где написано, что это всё невозможно.
По сравнению с в чём-то похожим PyWebView, Tauri не имеет папки с файлами, которую нужно носить с собой или распаковывать при каждом запуске, не злит антивирусы распаковками и не требует для работы открытый порт.
Ну и новичков порадует генератор новых проектов с поддержкой TypeScript, React, Vue, чёрта с рогами и без. Потому что под капотом там сидит Vite. Во время разработки есть Hot Reload.
Так, хватит мне тут изображать торговца орифлеймом, давайте лучше кодить. Сейчас я подразумеваю, что читатель - чукча фронтеэндщик, Rust не знает и не хочет, а сидит под Windows. И использует PowerShell. Для остальных вот официальные инструкции.
Ставим Rust. Идём на его сайт и качаем утилиту rustup (64 бит) , которая по сути есть инсталлятор Rust. Ставим всё по умолчанию. Под Windows Rust использует компилятор Microsoft, а тот в свою очередь идёт с большой пачкой библиотек, поэтому установка займёт долго и качает много.
Теперь поставим NodeJS ради его утилиты npm. Открываем терминал и набираем winget install OpenJS.NodeJS.LTS
Сработает - хорошо. Если winget опять отвалился, качаем NodeJS с его сайта.
Текстовый редактор оставлю на ваше усмотрение. Для VSCode есть экстеншн для Rust (rust-analyzer) и отдельный специально для Tauri, и ещё пригодится Better TOML.
Проверяем. Вводим в консоли cargo -V
(большая) потом npm -v
(маленькая). Если выводит номера версий - то всё в порядке.
Сам Tauri ставить не надо, он качается в проект.
Зрада! Даже если вы собираетесь писать на JavaScript, при создании проекта надо выбирать TypeScript. Это потому, что для проекта TypeScript ставится Vite и прочие ништяки, а проект на JavaScript суперминималистичный. Чтобы в TypeScript-проекте начать писать на JavaScript - достаточно переименовать файл из .ts в .js и убрать его из tsconfig.json.
Открываем в PowerShell папку, где у нас лежат поделки, и набираем npm create tauri-app@latest
Нам зададут несколько вопросов, везде нужно выбирать "TypeScript" "Vanilla" а остальное по умолчанию. Когда создание закончится, нужно перейти в папку проекта, набрать один раз npm install
а потом npm run tauri dev
Наш тестовый проект соберётся и запустится! Теперь, не выключая его, откроем в проекте файл index.html, поменяем в нём что нибудь (заголовок в h1 например) и сохраним. Сразу увидим изменения в запущенном приложении. Кстати, по правому клику в приложении доступно меню с отладочными инструментами. Оно есть только в debug сборке.
Давайте пройдёмся по созданному проекту. В корне у нас лежит index.html. Это HTML главного окна приложения. Честно говоря, не знаю, зачем он вынесен сюда, поскольку вся остальная web-часть убрана в папку src. Ещё мы видим надеюсь знакомые вам package.json и папку node_modules - следы жизни npm. В папку dist кладутся промежуточные стадии упаковки, эту папку не нужно бэкапить или класть в git. Но самая мякотка лежит в папке src-tauri.
В ней: cargo.toml - основной файл нашего проекта. В нём надо зайти и прописать название приложения, версию и автора - эти данные пойдут в метадату ЕХЕ-шника. Заодно в разделе dependencies убедитесь, что tauri у вас второй версии, а то были странные прецеденты.
cargo.lock руками трогать не надо, там список фактически используемых пакетов Rust.
Папка target - туда идут результаты компиляции. Это та папка, которую не надо бэкапить или класть в git. Если в корне проекта выполнить команду npm run tauri build
то в папке target/release появится финальная версия нашей программы, со всеми ресурсами упакованными внутрь. Мало того, в папке release/bundle будет программа, запакованная в .msi. Причём это умный инсталлятор, который проверит и предложит скачать все зависимости.
Папка icons содержит иконку нашей программы в вариантах под все платформы. К счастью, это безобразие нам не нужно делать руками. Нам нужна одна иконка в формате PNG размером 1024 пикселя с прозрачностями в интересных местах. Затем в корне проекта вызываем npm run tauri icon /path/to/app-icon.png
и все виды иконок появятся сами.
В src-tauri/src лежат непосредственно исходники на Расте. Их сегодня трогать почти не будем. Но можно заглянуть и поразиться минимальности. Изменения исходников на Расте не подхватываются на лету, приложение надо перезапускать.
И наконец файл tauri.conf.json, и capabilities - часть его. Это очень важный конфиг самого Tauri. Открываем.
productname, version, identifier
используются при сборке под мобильники. identifier должен быть уникальным в мире, поэтому проявите фантазию.
app - withGlobalTauri
это костыль, включённый по умолчанию. Давайте напишем туда false
и будет сразу делать как надо (ниже покажу).
window
- это параметры главного окна приложения. Их вообще-то много. А можно наоборот, удалить окно отсюда и создавать из кода, но это в другой раз.
Остальное сейчас не важно.
Не буду учить кодить на JavaScript. Вместо этого давайте покажу, как обойтись без бэкэнда на расте, с одним JS. Для этого нам понадобятся так называемые "плагины", они дают нам доступ к системе.
Открывам src/main.ts. Один плагин тут уже есть: api/core
. Он позволяет передавать данные на лету между бэком на расте и фронтом. Можно, конечно, было бы и сокет открыть для этого дела и любой другой способ, но через плагин намного проще и быстрее. Посмотрим, что происходит. Из плагина импортируем функцию invoke
и вызываем её с аргументом "greet"
. Что это за greet? Это функция, объявленная в файле src-tauri/lib.rs, а макрос #[tauri::command]
делает её доступной из JS.
Зрада! Если вы всё таки кодите на Расте, то помните, что при работе с Tauri нужно по максимуму пользоваться npm, а cargo вызывать только для самых Растовых операций вроде cargo add
. Иначе временами вылезают эфемерные баги с неопределённым положением в пространстве. В документации есть целый раздел об этом.
Давайте вместо функции на Расте, прочитаем текст из файла. Создадим текстовый файл, у меня это будет E:/name.txt. За работу с файлами у нас отвечает плагин fs.
В отличие от плагина core
, который есть всегда, большинство плагинов нужно установить и потом ещё включить. Сначала в корне проекта набираем npm run tauri add fs
а потом в capabilities/default.json делаем
"permissions": [
"core:default",
"shell:allow-open",
"fs:default",
{
"identifier": "fs:allow-open",
"allow": [{ "path": "**" }]
},
{
"identifier": "fs:allow-read",
"allow": [{ "path": "**" }]
}
]
Мы разрешили себе чтение из любого файла в системе. Лучше, конечно, по возможности ограничивать пути. Всё, теперь в main.ts можно изменить функцию greet на чтение из файла.
import { open } from "@tauri-apps/plugin-fs";
async function greet() {
if (greetMsgEl && greetInputEl) {
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
const file = await open("E:/name.txt" );
const buf = new Uint8Array(20);
const numberOfBytesRead = await file.read(buf); // 11 bytes
const text = new TextDecoder().decode(buf); // "hello world"
await file.close();
greetMsgEl.textContent = "Да здравствует товарищ" + text;
}
}
Ну и всё. Запускаем опять npm run tauri dev
если выключили. Теперь по нажатию кнопки должно приветствоваться имя из файла.