ByteNoteByteNote
Deno Desktop:Deno 2.9 内置的桌面应用打包能力,对标 Electron 和 Tauri

字节笔记本

2026年6月26日

Deno Desktop:Deno 2.9 内置的桌面应用打包能力,对标 Electron 和 Tauri

API中转
¥120

本文介绍 Deno Desktop,Deno 官方在 2.9 版本引入的桌面应用打包能力。它能把任意一个 Deno 项目——从一个单文件 TypeScript 到一个完整的 Next.js 应用——编译成自带运行时和渲染引擎的独立桌面程序,定位上对标 Electron 和 Tauri,但在设计取舍上走了一条更克制的路。

项目简介

Deno Desktop 从 Deno v2.9.0 开始内置,不需要额外安装 CLI。它的定位很明确:既然 Web 技术是世界上最普及的 UI 工具包,而基于 Web 栈做桌面应用(Electron、Tauri、Electrobun)又各有各的妥协,那不如由运行时官方来把这些取舍统一拿捏好。

它的核心能力是把一个 Deno 项目编译成可分发的二进制文件,这个文件里同时打包了你的代码、Deno 运行时和一个 Web 渲染引擎。运行时默认用操作系统自带的 WebView(体积小),需要跨平台一致渲染时可以切到内置的 Chromium(CEF)后端。值得一提的是,得益于 Deno 的 Node 兼容层,整个 npm 生态依然可用,这是它和 Tauri 这类方案的一个显著差异。

核心特性

  • 小体积默认,完整 Node 兼容 —— 默认 WebView 后端直接复用系统的渲染引擎,二进制体积小;同时通过 Deno 的 Node 兼容层,整个 npm 生态照常使用。需要 macOS/Windows/Linux 渲染完全一致时,再切到 CEF 后端
  • 框架自动识别 —— 把 deno desktop 指向 Next.js、Astro、Fresh、Remix、Nuxt、SvelteKit、SolidStart、TanStack Start 或 Vite SSR 项目,它能自动跑起来:release 模式起生产服务器,--hmr 下起带热更新的开发服务器,无需改动现有 Web 项目代码
  • 进程内绑定取代 IPC —— 后端与 UI 的通信走进程内通道,而不是基于 socket 的 IPC。值在跨越调用边界时仍会做编码,但 Deno 代码和 webview 之间没有跨进程往返
  • 单机交叉编译 —— 同一台机器就能构建 macOS、Windows、Linux 三个平台的产物,后端按需下载,不必本地构建
  • 内置差分自动更新 —— 发布一个 latest.json 清单和 bsdiff 补丁,运行时会自动轮询、应用更新,启动失败时自动回滚

技术栈

  • Deno 运行时 —— 整个方案的基础,负责执行 TypeScript/JavaScript 后端代码
  • 系统 WebView / CEF —— 渲染前端 UI 的引擎,默认走系统原生,可选 Chromium
  • V8 引擎 —— Deno 内置的 JS 执行引擎
  • Rust(Tauri 式的 FFI 层) —— 原生窗口、菜单、托盘等系统能力的绑定

前置要求

  • Deno 2.9.0 及以上 —— 这是 Deno Desktop 的最低版本,旧版本用不了,需先升级
  • 各平台额外依赖 —— macOS 编译需要 Xcode Command Line Tools;Windows 需要 MSVC 工具链;Linux 需要 webkit2gtk 等系统库

安装指南

升级或安装 Deno

bash
# 已装旧版,升级到最新
deno upgrade

# 全新安装(macOS / Linux)
curl -fsSL https://deno.land/install.sh | sh

# Windows(PowerShell)
irm https://deno.land/install.ps1 | iex

确认版本:

bash
deno --version   # 需 >= 2.9.0

Deno Desktop 是运行时内置能力,装好 Deno 就直接可用,没有单独的包要装。

快速开始

最小可运行的桌面应用,只需一个文件:

typescript
// main.ts
Deno.serve(() =>
  new Response("<h1>Hello, desktop</h1>", {
    headers: { "content-type": "text/html" },
  })
);

编译成桌面程序:

bash
deno desktop main.ts

这会生成一个可执行文件,双击或命令行运行,它会弹出一个窗口,指向 Deno.serve() 绑定的本地 HTTP 服务:

bash
./main      # macOS / Linux
.\main.exe  # Windows

值得注意的设计细节:Deno.serve() 会自动绑定到 webview 要导航的地址,所以你不需要手动指定端口或主机名,运行时帮你把这件事处理好了。

使用示例

场景一:把现有 Web 框架搬到桌面

这是 Deno Desktop 最省心的场景。假设你已有一个 Next.js 项目,直接:

bash
# 框架被自动识别,无需配置
deno desktop ./my-next-app

它会在 release 模式下启动生产服务器,把窗口指过去。开发时加 --hmr 就能得到带热重载的开发体验,跟你平时 next dev 几乎一样,但产物是桌面 App。

支持的框架覆盖了当前主流的 SSR/SSG 方案:Next.js、Astro、Fresh、Remix、Nuxt、SvelteKit、SolidStart、TanStack Start,以及纯 Vite SSR。

场景二:前后端进程内通信(Bindings)

不同于 Electron 那套基于 IPC 的 ipcRenderer / ipcMain,Deno Desktop 用的是 bindings 机制——前端直接调用 bindings.<name>(),执行的是同一进程内的 Deno 代码:

typescript
// 后端 Deno 代码注册一个 binding
// 前端在 webview 里:bindings.readFile("/path/to/file")

这种设计省去了跨进程的消息序列化往返,调用感受更接近本地函数。当然,值在跨越调用边界时仍会做编码(Deno 侧和 webview 侧是两套 JS 运行时),但不存在 socket 层的往返开销。

场景三:原生系统集成

桌面应用少不了系统能力,Deno Desktop 把这些都做了原生封装:

能力API
多窗口管理Deno.BrowserWindow 生命周期与事件
应用菜单/右键菜单Menus 模块
系统托盘/DockTray and dock 模块
原生弹窗prompt() / alert() / confirm() 映射为系统弹窗
系统通知Web Notification API 映射为原生通知

场景四:自动更新

发布时维护一个 latest.json 清单,配合 bsdiff 差分补丁:

typescript
// 在应用里调用自动更新
await Deno.autoUpdate();

运行时会轮询清单、下载补丁、应用更新;如果更新后启动失败,会自动回滚到上一个可用版本。这把 Electron 用户经常要自己接 Sparkle / Squirrel 那一摊的事,直接内化了。

和 Electron / Tauri 怎么比

既然是桌面方案,绕不开和两位前辈的对比。

对比 Electron:Electron 自带完整 Chromium,所以跨平台渲染完全一致,但二进制动辄 100MB+。Deno Desktop 默认走系统 WebView,体积小很多,牺牲的是不同平台渲染细节可能略有差异;真需要一致渲染时切 CEF,又回到 Electron 那种"自带头"的模式,但这是可选项而不是默认项。

对比 Tauri:两者都用系统 WebView 的思路相近,但 Tauri 后端是 Rust,等于要求你跨语言开发(前端 JS、后端 Rust);Deno Desktop 前后端都是 TypeScript/JavaScript,且完整支持 npm 生态,对纯 JS 背景的团队更友好。

一个独特优势是框架集成:Deno Desktop 能直接识别主流 SSR 框架并自动跑起来,这意味着把已有 Web 项目转桌面几乎零成本。Tauri 和 Electron 通常需要你自己组织前后端如何衔接。

小结

Deno Desktop 的出现,本质上是 Deno 把"运行时该管的事"往外延伸了一步——既然开发者用 Deno 写后端、用 Web 技术写界面,那把这两者打包成桌面成品就应该是运行时分内的事,而不是再引入一个第三方壳。

对已有 Deno/TypeScript 项目的团队来说,它的吸引力主要在两点:一是零成本复用 npm 生态和现有框架,二是单机交叉编译和内置自动更新省掉了大量打包分发的基础设施工作。当前局限主要在于还很新(2.9 才引入),生态和踩坑资料不如 Electron/Tauri 丰富,适合愿意尝鲜、对体积和更新体验敏感的团队先用起来。

项目链接

分享: