Каждый разработчик, решавший упаковать небольшую веб-утилитку в десктопное приложение, сталкивался с тяжелым компромиссом. Классический Electron приносит с собой полноценный движок Chromium и рантайм Node.js, из-за чего простейший таймер или клиент заметок мгновенно раздувается до 150–200 мегабайт на диске и жадно расходует оперативную память. Фреймворк Tauri предлагает отличную альтернативу на базе системного веб-компонента, но вынуждает веб-программиста писать системную часть на Rust. Открытый проект TinyJS предлагает третий путь: нативные десктопные приложения весом всего около 6 МБ, где и интерфейс, и бэкенд пишутся исключительно на чистом JavaScript.
Инструментарий TinyJS спроектирован так, чтобы минимизировать накладные расходы как при дистрибуции, так и во время работы. Вместо того чтобы носить с собой тяжелый браузер, приложение опирается на движок отображения, уже встроенный в операционную систему: WKWebView на macOS, WebKitGTK на Linux и WebView2 на Windows.
Движок txiki.js: системный JavaScript без тяжелого рантайма
Сердцем бэкенда в TinyJS стал txiki.js (tjs) — компактный и производительный JavaScript-рантайм, объединяющий легковесный интерпретатор QuickJS и кроссплатформенную библиотеку асинхронного ввода-вывода libuv (ту самую, что отвечает за циклы событий в Node.js).
Благодаря txiki.js разработчик получает полноценный доступ к операционной системе: работе с файлами, сетевым сокетам, управлению дочерними процессами и даже прямому вызову функций из сторонних динамических библиотек на Си через механизм FFI. При этом сам исполняемый файл рантайма занимает считанные мегабайты и стартует практически мгновенно.
Инициализация оконного приложения в TinyJS сводится к лаконичному скрипту, который настраивает параметры окна и указывает файл верстки:
// app.js — точка входа бэкенда на txiki.js
import * as tiny from '@tinyjs/app';
const window = await tiny.createWindow({
title: 'Монитор системы',
width: 800,
height: 600,
resizable: true,
url: 'ui/index.html'
});
// Регистрация нативного пункта меню
window.setMenu([
{
label: 'Действия',
submenu: [
{ label: 'Обновить данные', click: () => window.emit('refresh-stats') },
{ label: 'Выход', role: 'quit' }
]
}
]);
Безопасность без открытых портов: общение через сокеты
Многие легковесные оболочки для веб-приложений идут по пути наименьшего сопротивления: поднимают на компьютере пользователя локальный HTTP-сервер на случайном порту (localhost:3000) и открывают его во встроенном браузере. Однако такой подход создает брешь в безопасности: любой сайт, открытый пользователем в обычном браузере, может попытаться отправить запрос на этот локальный порт и выполнить вредоносный код через атаку типа CSRF.
TinyJS решает проблему межпроцессного взаимодействия (IPC) принципиально иначе. Фронтенд и бэкенд общаются через приватный Unix domain socket (или именованный пайп в Windows), расположенный во временной директории приложения с ограниченными правами доступа. Никакие сетевые порты не открываются наружу, что исключает сетевые сканирования и несанкционированный доступ:
// ui/main.js — код интерфейса, выполняемый внутри системного WebKit
import { ipc } from '@tinyjs/client';
const statusEl = document.getElementById('status');
const actionBtn = document.getElementById('btn-action');
// Отправка команды системному процессу через защищенный сокет
actionBtn.addEventListener('click', async () => {
statusEl.textContent = 'Сбор метрик...';
const response = await ipc.invoke('get-system-info');
statusEl.textContent = `Память: ${response.freeMemory} МБ свободно`;
});
// Прослушивание событий из меню приложения
ipc.on('refresh-stats', () => {
actionBtn.click();
});
Особенности работы на Linux и мультимедиа
На платформе macOS проект демонстрирует максимальную стабильность и органично вписывается в экосистему Apple. Поддержка Linux и Windows активно развивается в рамках открытой бета-версии.
Разработчикам под Linux важно учитывать системные зависимости: для запуска требуется пакет libwebkit2gtk-4.1-0. Кроме того, если интерфейс работает с аудиофайлами в сжатых форматах вроде AAC или M4A, в системе должны присутствовать кодеки GStreamer (gstreamer1.0-plugins-bad). Из-за особенностей диспетчеризации потоков в Linux разработчики TinyJS рекомендуют воспроизводить аудио через стандартный HTML-элемент <audio>, не перегружая планировщик сложными графами Web Audio.
TinyJS демонстрирует, как грамотное использование системных примитивов позволяет вернуть десктопным программам легкость и моментальную отзывчивость, не заставляя инженеров отказываться от привычного стека веб-технологий.
