博客

Pake 的原理:一个网址是怎么变成桌面应用的

原理与选择 · · 约 7 分钟

Pake 并不改写网站。pake 命令做的事是复制一份预先写好的 Tauri 应用模板,把你给的选项写进配置,用 Rust 编译,再打成安装包,装好之后它用操作系统自带的 Web 视图打开你的网址。应用之所以小,是因为浏览器引擎不在安装包里,它的大部分限制也都能从这一点解释。

构建过程

先用 pnpm install -g pake-cli 装好命令行(npm 也行),再运行 pake https://example.com --name Example。入门指南里列了前置条件,Node.js 20.9 或更高、Rust 1.85 或更高,以及各平台的编译工具。Rust 缺失时,第一次运行会问你要不要装。

命令行接着依次做五件事。先校验网址和选项;然后在系统临时目录下建一个临时工作区,把 Tauri 模板复制进去,所以你装的命令行本身不会被改动;再确定应用名字和图标,不传 --icon 就去抓网站的 favicon;然后把你的选项合并进工作区里的配置文件,并在那里跑 Tauri 构建;最后把生成的安装包复制到你运行命令的目录,并删掉工作区。

一台从没构建过 Pake 应用的机器,第一次要等好几分钟,命令行提示 macOS 和 Linux 大约 5 到 10 分钟,Windows 是 10 到 15 分钟,因为 Rust 要把 Tauri 和它的依赖都编译一遍。编译产物保存在命令行包的 src-tauri/target 目录里,后面的构建才会快。

生成的配置里有什么

模板放在命令行包的 src-tauri 目录,里面有一个 Rust 项目、带默认值的 pake.json、tauri.conf.json,以及每个平台各一份的配置文件,还有 src-tauri/src/inject 下的一组脚本。Pake 把这些文件复制到工作区的 .pake 目录再改写。

pake.json 放 Pake 在 Tauri 之上加的东西,包括网址、它是网页还是本地文件、窗口大小(默认 1200 乘 780)、窗口置顶、深色模式、托盘选项、User-Agent,以及你要注入的文件。tauri.conf.json 放 Tauri 需要的东西,包括产品名、应用标识、图标路径和打包目标。标识由网址和名字推出来,所以同一个网站用不同的 --name 能装成互不相干的两个应用。

有些选项只在特定平台生效,生成配置时按平台处理而不是报错,比如 --hide-title-bar 只对 macOS 有效,--hide-window-decorations 只对 Windows 和 Linux 有效,--hide-on-close 在 macOS 默认开、其他系统默认关。完整选项见选项参考,常用的几个在自定义网页应用的窗口里有例子。

编译进应用的是什么

这是最容易让人意外的一点。应用启动时并不会去读配置文件。CLI 构建的 Rust 代码在 cli-build 这个 Cargo feature 下,用 include_str! 在编译时把 .pake/pake.json 和 .pake/tauri.conf.json 嵌进二进制,所以改选项就要重新构建。

注入脚本也是同样的道理。运行时应用用 Tauri 的窗口构建器建窗口,把一个 window.pakeConfig 对象交给页面,再把 src-tauri/src/inject 里的脚本注册为初始化脚本,其中有链接处理和 OAuth 识别(link_policy.js、auth.js、frame_links.js)、下载状态用的提示条、macOS 和 Linux 上的全屏桥接、键盘和导航处理(event.js)、隐藏滚动条并给拖动区域加样式的 CSS(style.js)、主题跟随,以及开启 --enable-find 时才有的页内查找栏。你用 --inject 传的文件会被拼进 custom.js,不传时它是空的。

分两组的示意图:构建时 pake 命令生成配置,再和 Tauri 模板、Rust 一起编译成安装包;运行时安装好的应用打开原生窗口,窗口里是系统自带的 Web 视图,运行 Pake 注入的脚本并加载网站地址

配置和脚本在构建时就编译进了安装包,运行时应用只是系统自带 Web 视图外面的一个窗口。

系统自带的 Web 视图

Pake 的窗口就是 Tauri 窗口,Tauri 用所在平台的 Web 视图绘制网页内容。Tauri 的 webview 版本页面列出的是 macOS 上的 WKWebView、Windows 上的 WebView2 和 Linux 上的 WebKitGTK。Pake 没有自带浏览器引擎,网站就跑在这个引擎里,Pake 的脚本叠在上面。

这也是同一个页面在应用里可能和浏览器里略有不同的原因,是 Cloudflare 验证在 Linux 上可能转圈的原因,也是不管加什么参数,Google 登录在嵌入视图里可能被拒的原因。Tauri 与 Electron 包装网站的区别比较了两种选择各自的代价,WebView2 是什么讲 Windows 上的运行时,设置 User-Agent讲你能影响网站如何看待应用的少数手段之一。

打包,以及应用为什么小

打包步骤按当前平台选目标。macOS 默认是 .dmg,--targets app 则输出 .app;Windows 是 .msi;Linux 默认按发行版决定,Debian 和 Ubuntu 上是 deb 加 appimage,Fedora 一类是 rpm 加 appimage,也可以选 zst。命令行还能用 JSON 输出结果,包括每个产物的路径、大小和格式。

安装包里是编译好的 Rust 二进制、你的图标,以及嵌进去的配置和脚本,没有 Chromium。Pake 的 README 说安装包在磁盘上通常小于 10 MB,FAQ 把话说得很清楚,这是安装包大小,不是内存占用,一个很重的单页应用在同一引擎的任何浏览器里打开,内存开销差不多,Pake 自己加的很少。

构建时和运行时各跑什么

构建时跑的是 Node 和 Rust,也就是命令行、Tauri 构建和打包器,这些在运行成品应用时都用不上,拿到应用的人不需要装 Node 或 Rust。

运行时只有 Rust 二进制、系统 Web 视图和网站本身,网站每次启动都从你的网址加载。打包的网址是主页,不过网页应用默认会记住主窗口最后访问的网址并在下次打开,想每次都回到主页就加 --no-restore-last-url,这个网址保存在应用数据目录下的 last-url.txt,无痕应用和本地 HTML 应用不会恢复。Cookie、本地存储和登录状态归 Web 视图管,具体位置取决于平台和 Web 视图的数据存储。

打包本地目录时,pake ./dist --name MyTool 会在构建前把你的文件放进模板的 dist 目录,结束后恢复原样,目录最上层必须有 index.html。

出问题时怎么查

构建失败多半出在工具链这边,Rust 低于 1.85、Windows 上缺 Visual Studio Build Tools、Linux 上缺 WebKitGTK 开发包、Windows 上第一次构建超时,这些在 FAQ 里都有。AppImage 构建失败时,命令行会自动带上 NO_STRIP=1 重试一次,因为 strip 这一步最常出问题,仍然失败的话它建议改用 --targets deb。

应用能构建出来但网站表现不对,原因几乎总是引擎或者网站本身,不是构建。先在 macOS 的 Safari 或 Windows 的 Edge 里试这个页面,那里也不行,打包也帮不上忙;那里正常的话,再看站点是不是需要让另一个域名留在应用内(--safe-domain),或者需要弹出窗口(--new-window),入门指南里有说明。

确认构建结果,可以打开安装包、看文件大小、启动应用;确认配置生效,把窗口大小、标题栏和置顶行为对着你给的选项看一遍。如果你需要每个系统上都是同一个版本的 Chromium,Pake 就不合适,基于 Electron 的包装工具更对路。

常见问题

Pake 应用运行时需要 Node.js 或 Rust 吗?

不需要,它们只在构建时用到。成品是编译好的二进制,使用系统的 Web 视图。

构建之后还能改应用的设置吗?

CLI 构建的应用不能通过设置文件改,因为配置是编译进去的,换选项就重新构建。换一个名字会得到一个独立的应用。

网站的数据存在哪里?

存在该应用对应的系统 Web 视图存储里。在 Windows 上,命令行文档说打包后的应用使用自己的 WebView2 配置,和 Chrome、Edge 的不共享。