Разработка десктопных приложений с помощью deno desktop
Deno desktop собирает TypeScript-приложения в нативные десктопные бинарники с webview или CEF, поддержкой фреймворков, кросс-сборкой и ограничениями.
deno desktop компилирует проект на Deno в самодостаточное десктопное приложение: ваш код, рантайм Deno и движок рендеринга в одном бинарнике на каждую платформу. Команда появилась в Deno 2.9. От Electron и Tauri её отличает то, что движок рендеринга выбирается на этапе сборки. Вы берёте либо системный WebView, либо встроенный Chromium — и ни Electron, ни Electrobun, ни Tauri, ни Dioxus такого переключателя не предлагают.
Каждый, кто выпускал приложение на Electron, знаком с разговором про стомегабайтный инсталлятор, а каждый, кто выпускал приложение на Tauri, знаком с багом, который воспроизводится только в WebKitGTK. Эти два фреймворка находятся на противоположных концах одной оси, и до сих пор выбор фреймворка означал выбор движка рендеринга навсегда.
Это первое знакомство с третьим вариантом, рассчитанное на читателей, которые уже разбираются в компромиссе между Electron и Tauri. Здесь разбирается, что производит эта команда, какая минимальная программа демонстрирует модель работы, во сколько мегабайт обходится каждый бэкенд, какие проекты на фреймворках принимаются без изменений, как устроена кросс-компиляция и чего пока не хватает. Сам спор Electron против Tauri разобран в отдельном сравнении Electron и Tauri.
Ключевые выводы
deno desktopвышел в составе стабильного релиза Deno 2.9.0 25 июня 2026 года, и пост о релизе по-прежнему помечает его как экспериментальный, отмечая, что часть платформенных возможностей ещё не реализована.- Бэкенд
webview, используемый по умолчанию, рендерит через WebView2 в Windows, WKWebView в macOS и WebKitGTK в Linux; опциональный бэкендcefвстраивает Chromium ради идентичного рендеринга на всех платформах. - На странице сравнения от Deno приложение на WebView оценивается примерно в 40 МБ, а приложение на CEF — примерно в 150 МБ, против ~100 МБ+ у Electron и ~2–10 МБ у Tauri.
- Обработчик
Deno.serve()внутри десктопной точки входа не принимает ни порт, ни хост: рантайм сам привязывает его к адресу, который загружает окно. --targetи--all-targetsобеспечивают кросс-компиляцию под пять платформенных triple с любого хоста без Rust-тулчейна; единственное исключение, привязанное к хосту, —.dmgдля macOS.
Что такое deno desktop?
Укажите deno desktop на точку входа Deno или на проект веб-фреймворка — и на выходе получите десктопное приложение, которое рисует свой интерфейс в webview, а логику выполняет в Deno. Пост о релизе 2.9 представляет эту возможность как главную новинку и в том же разделе помечает её как экспериментальную, с ещё не стабилизировавшимся API. Она попала именно в стабильную версию 2.9.0, а не в canary, что зафиксировано в заметках о релизе v2.9.0 под пунктом feat: deno desktop subcommand.
В бинарник для каждой платформы попадают три вещи: ваш код, рантайм Deno и бэкенд рендеринга. Обмен данными между стороной Deno и webview идёт через внутрипроцессные каналы, а не через сокетный IPC, — это иная модель по сравнению с передачей сообщений между main- и renderer-процессами в Electron. Нативные примитивы вроде Deno.BrowserWindow и Deno.Tray встроены в рантайм, поэтому для управления окнами и иконок в системном трее не нужен ни один сторонний пакет.
Минимальная программа на deno desktop
Минимальное десктопное приложение — это один обработчик Deno.serve(), возвращающий HTML, плюс одна команда.
// main.ts
Deno.serve(() =>
new Response("<!DOCTYPE html><h1>Window one</h1>", {
headers: { "content-type": "text/html" },
})
);
deno desktop main.ts
Обратите внимание на отсутствующий аргумент. В обычном сервере на Deno вы передали бы порт; здесь его не указывают, потому что в десктопной точке входа рантайм сам передаёт обработчику адрес, на который уже нацелено окно. Скомпилированное приложение открывает нативное окно на этом локальном сервере. Это единственная неочевидная часть модели программирования: HTTP-сервер выступает транспортом для UI, а рантайм сам связывает оба конца.
Что выбрать: бэкенд webview или cef?
Движок рендеринга — решение на этапе сборки, и именно поэтому deno desktop занимает нишу, которую не закрывает ни один из конкурентов. Electron встраивает только Chromium, Tauri использует только системный WebView. deno desktop умеет и то и другое; выбор задаётся флагом --backend или полем desktop.backend в deno.json.
deno desktop main.ts # webview (default)
deno desktop --backend cef main.ts # bundled Chromium
На странице о бэкендах перечислены движки, стоящие за вариантом по умолчанию: WKWebView в macOS, WebView2 в Windows, WebKitGTK в Linux. Там же задокументированы два ограничения этого бэкенда, важные при его оценке: DevTools доступны только в CEF, а WebGPU в Linux требует CEF. Бэкенд cef кладёт копию Chromium Embedded Framework внутрь бандла приложения; на той же странице объём одного только фреймворка оценивается в ~150 МБ.
На странице сравнения Deno приводит примерные размеры получающихся приложений:
| Инструмент | Движок | Размер приложения (по данным Deno) |
|---|---|---|
deno desktop, webview | Системный WebView | ~40 МБ |
deno desktop, cef | Встроенный Chromium | ~150 МБ |
| Electron | Встроенный Chromium | ~100 МБ+ |
| Tauri | Системный WebView | ~2–10 МБ |
Страница о дистрибуции даёт отдельную точку отсчёта: hello-world на бэкенде WebView весит около 66 МБ, а --compress уменьшает этот размер до 19 МБ. Все эти цифры стоит воспринимать как данные самой Deno, а не как замеры вашего приложения.
Правило в одну строку из поста о релизе гласит: оставайтесь на webview, если только вам не нужен одинаковый движок везде. Если дополнить его задокументированными ограничениями, получается рабочий критерий: по умолчанию берите webview; переходите на cef, когда ваш UI зависит от специфики рендеринга Chromium, когда вы не можете протестировать приложение на всех трёх системных движках, когда вам нужны DevTools во время разработки или когда нужен WebGPU в Linux. Цена перехода — разница между двумя строками таблицы выше.
Какие фреймворки распознаёт deno desktop?
Будучи направленной на существующий проект фреймворка, команда deno desktop . определяет фреймворк по конфигурационному файлу или package.json, встраивает результат сборки и запускает продакшен-сервер фреймворка в качестве обработчика Deno.serve(). Для Next.js, Astro, Fresh и Nuxt в заметках по отдельным фреймворкам показана только собственная команда сборки фреймворка, за которой следует deno desktop ., — без адаптеров и дополнительной конфигурации. SvelteKit тоже распознаётся, но только через вывод адаптера Deno Deploy или Node-адаптера; для React Router нужен совместимый с Deno app/entry.server.tsx.
Сборку фреймворка нужно запускать первой. Команда упаковывает то, что произвела эта сборка; она не станет вызывать next build или astro build за вас.
npx next build # produce .next/
deno desktop . # package the built server
deno desktop . --hmr # development: framework dev server with hot reload
С флагом --hmr окно приложения смотрит напрямую на dev-сервер самого фреймворка, поэтому разработка ощущается почти как работа во вкладке браузера: состояние переживает правку, fast refresh работает, а ошибки приходят через привычный оверлей.
Как кросс-компилировать приложения deno desktop?
--target <triple> собирает под одну другую платформу, а --all-targets — под все поддерживаемые, с любого хоста и без Rust-тулчейна. На странице о дистрибуции перечислены пять целей: aarch64-apple-darwin, x86_64-apple-darwin, x86_64-pc-windows-msvc, aarch64-unknown-linux-gnu и x86_64-unknown-linux-gnu.
deno desktop --target x86_64-pc-windows-msvc main.ts
deno desktop --all-targets main.ts
Механизм здесь — загрузка, а не компиляция. Для запрошенной цели CLI скачивает готовый denort и готовый архив бэкенда, проверяя оба по SHA-256-хешам перед использованием. Именно поэтому это работает там, где не работают Tauri и Dioxus. Их Rust-тулчейны должны компилировать код на целевой платформе, так что каждой ОС нужна своя сборочная машина. Electron умеет кросс-сборку через electron-builder, так что контраст здесь именно с инструментами на Rust. Единственное исключение на стороне Deno — .dmg для macOS, который вызывает hdiutil и потому должен собираться на Mac.
Насколько это зрелое решение, если честно
На Electron работают Slack, Visual Studio Code и Notion; за Tauri 2 стоят годы релизов и поддержка мобильных платформ; deno desktop появился в 2.9.0, и каждый патч-релиз ветки 2.9 с тех пор нёс исправления для desktop, включая 2.9.6. Документация откровенно говорит о том, чего пока нет.
С форматами вывода дела обстоят лучше, чем можно предположить по списку пробелов на странице сравнения. Страница о дистрибуции документирует .app и .dmg для macOS, каталог приложения или .msi для Windows, а также каталог приложения, .AppImage, .deb или .rpm для Linux — формат выбирается по расширению в --output. Инсталляторы .msi, .deb и .rpm появились уже в самой версии 2.9.0, согласно заметкам о релизе.
Подтверждённые пробелы:
- Автообновление в Windows. Обновление до конца доводят только macOS и Linux: они применяют подготовленный патч и, если новая версия не запускается, откатываются к старой. Windows скачивает и подготавливает патч, но так и не подменяет им приложение, поэтому при следующем запуске ничего не меняется. Страница об автообновлении советует считать автообновление в Windows пока не поддерживаемым.
- Нотаризация. Подпись выполняется автоматически на хосте с macOS, но раздел о подписи кода отмечает, что нотаризацию всё равно приходится делать вручную, отдельным шагом с
xcrun notarytool submit. - Мобильные платформы. Целей под iOS и Android нет, тогда как у Tauri 2 есть обе.
- Защищённое хранилище, запросы разрешений во время выполнения, общий рантайм CEF. Страница сравнения перечисляет все три пункта как отсутствующие или запланированные; общий рантайм — как раз то, что уменьшило бы размер CEF-приложений, но это обещание, а не релиз.
Кому стоит попробовать deno desktop уже сейчас?
Пробуйте прямо сейчас, если вы уже используете Deno, ваша команда пишет на TypeScript, а не на Rust, и речь идёт о внутреннем инструменте или десктопной обёртке вокруг существующей кодовой базы на Next.js, Astro, Fresh или Nuxt, где сборка на WebView в 40 МБ приемлема, а аудитория на macOS или Linux закрывает вопрос с автообновлением. Подождите, если вы поставляете продукт пользователям Windows, которым нужны обновления «на месте», если вам нужны мобильные платформы из той же кодовой базы или нужен конвейер дистрибуции с многолетним багажом инструментов подписи и создания инсталляторов. Ярлык «экспериментальный» в посте о релизе точен: модель продумана и команды работают так, как задокументировано, но поверхность API ещё может меняться между патч-релизами.
Заключение
deno desktop — действительно третий вариант, потому что он отделяет выбор движка рендеринга от выбора фреймворка и назначает задокументированную цену каждой стороне этого выбора. Дешевле всего оценить его так: запустить deno desktop . внутри уже имеющегося проекта на фреймворке — один раз на бэкенде по умолчанию и один раз с --backend cef — и сравнить два получившихся артефакта с учётом перечисленных выше пробелов.
Часто задаваемые вопросы
Как webview вызывает код Deno в приложении на deno desktop?
Через биндинги. На стороне Deno вы привязываете обработчик к окну вызовом win.bind(name, handler); затем JavaScript на странице вызывает bindings.name(args) и получает промис с тем, что вернул обработчик. У каждого окна свой набор биндингов, поэтому обработчик, зарегистрированный на одном Deno.BrowserWindow, не виден другому. Вызов идёт по внутрипроцессным каналам, а не через сокетный IPC, и когда обработчик выбрасывает исключение, до webview доходит обычный объект с полями name, message и stack, а не настоящий Error.
Что такое бэкенд raw в deno desktop и когда его использовать?
Он запускает десктопное приложение вообще без веб-движка. У вас остаются окна, события ввода и нативный API, но рендерить HTML некуда: нет ни webview, ни автоматической привязки Deno.serve(), ни прокси биндингов. Он подходит приложениям, которые рисуют собственный интерфейс средствами WebGPU, Skia или собственного кода отрисовки. Выбрать его можно только через поле desktop.backend в deno.json, поскольку флаг --backend принимает лишь cef и webview.
Можно ли переключать приложение на deno desktop между бэкендами webview и cef без изменения кода?
Да. Страница о бэкендах в документации Deno рассматривает CEF и WebView как взаимозаменяемые: окна, биндинги, события, навигация и выполнение JS ведут себя одинаково на обоих, и только бэкенд raw нарушает эту переносимость. При сборке под бэкенд или цель, которые вы ещё не использовали, сначала скачивается готовый архив — в случае CEF это несколько сотен мегабайт, — с проверкой контрольной суммы и сохранением в кеш-каталоге Deno, так что последующие сборки обходятся без загрузки.
Действуют ли разрешения Deno внутри приложения на deno desktop?
Да, но они берутся из разрешений, вкомпилированных в бинарник, а не из запросов пользователю. Биндинг выполняется внутри рантайма Deno с теми правами, что были выданы процессу, поэтому обработчику, читающему файл, нужен доступ на чтение, выданный при запуске, и ничто из происходящего в webview не может его расширить. В документации прямо сказано, что отдельный запрос разрешений во время выполнения не появляется, — поэтому считайте всё, что биндинг принимает со страницы, недоверенным вводом и валидируйте это.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k