Дайджесты новостей
Концептуальная иллюстрация TinyJS: легковесное десктопное приложение весом 6 мегабайт, общающееся с системой через изолированный Unix-сокет.

TinyJS: нативные десктопные приложения на JavaScript весом 6 МБ без Chromium

Каждый разработчик, решавший упаковать небольшую веб-утилитку в десктопное приложение, сталкивался с тяжелым компромиссом. Классический 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 демонстрирует, как грамотное использование системных примитивов позволяет вернуть десктопным программам легкость и моментальную отзывчивость, не заставляя инженеров отказываться от привычного стека веб-технологий.