从Pake源码看web应用如何转换为原生应用

2025 年 11 月 23 日

Pake 是我很久之前就看到的一个项目,项目是这样介绍自己的:Turn any webpage into a desktop app with one command, supports macOS, Windows, and Linux。即:用一条命令将任意网页转换为桌面应用,支持 macOS/Windows/Linux

没看源码之前,这句话让我有点不解。我知道 Pake 是基于 Tauri 实现的,而 Tauri 的核心,就是用 rust 启动操作系统本身的 WebView,在这个 WebView 中运行一个 web 应用。也就是把 web 应用转换为原生应用。

既然用 Tauri 简单修改一下就可以达成把 web 应用转换为原生应用这个目的,那么为什么还要有 Pake 呢?除了一条命令这点,它比 Tauri 又多做了哪些事情呢?今天看了一下源码,总算看出来一点门道。

注:本文只是看源码过程中的一个副产品,并非一篇完整的源码分析,所以疏漏难免。

整体工程

先看工程结构,虽然看起来很像 Tauri 工程,但实际上,Pake 是一个 nodejs 工程。其 CLI 的源码是在 /bin 目录下的 ts 代码。

Pake 的工作可以简单理解为:根据输入的参数,生成一套 Tauri 应用的源码,然后编译,并得到 Tauri 应用的二进制文件或安装包

因此,在 src-tauri 目录下的源码,可以理解为目标 Tauri 应用源码的模板。

目标 Tauri 应用源码入口分析

写过 Tauri 应用的应该不难理解,从 V3.5.1 的 /src-tauri/src/lib.rs 看进去,可以明显看出,相对于默认的 Tauri 应用模板,Pake 生成的应用在启动时,做了以下事情:

  • 将 Pake 配置转换为 Tauri 配置文件

  • 多进程/单进程开关

  • 添加了一组 Tauri 的 plugin,包括 oauth / http / shell / notification

  • 为后端添加了 3 个接口:download_file / download_file_by_binary / send_notification,其中:

    • download_file 和 download_file_by_binary 的区别在于,要下载的数据到底是链接,还是前端的 blob 数据
    • send_notification 的目的是调用系统原生的通知接口
  • 调整窗口、系统托盘(system tray)以及快捷方式相关,在调整窗口时,主要还做了以下几件事:

    • 根据设置选择打开外部 web 链接还是本地文件
    • 注入 window.pakeConfig 对象,以及几个 js 脚本
    • 调整浏览器参数,打开一些 feature
  • 处理 window 关闭事件,根据配置选择是退出还是最小化到托盘

前端注入代码分析

调整窗口时注入了几个 js 文件,用途包括:

  • component.js:添加了一个 pakeToast 接口,用于弹出 toast,显示一些提示
    • 该接口仅在 rust 后端代码执行过程想要通知使用者时被调用,看起来目前主要是通知下载结果
  • custom.js:允许项目使用者自定义的 js。默认为空
  • event.js:所有事件处理,例如:
    • 键盘快捷键,实现一些页面浏览的控制,如前进/后退/放大/缩小/滚动到顶部或底部,等等。
    • 链接点击,对于下载链接,使用后端添加的接口完成下载,避免打开新浏览器页面。
    • 右键上下文菜单。
    • 特定区域(pake-top-dom)拖拽处理。
  • style.js:注入 css,并根据先前注入的 pakeConfig 调整页面样式

结论

所以,回到最初的问题,Pake 比 Tauri 多做的事情,就是 Web 应用转换为原生应用时,需要处理的一些问题点:

  • 窗口处理:web 应用在浏览器中运行,因此窗口样式是由浏览器控制。在 WebView 窗口中,可能需要做一些改动,比如拖拽区域。
  • 通知处理,包括:
    • 前端应用调用 window.Notification 接口的实现。
    • 后端应用调用前端 Toast 接口的实现。
  • 下载处理:启动后台下载线程,避免让浏览器直接下载或打开新窗口。
  • UI 处理:样式调整等。
  • 其他尚未注意到的前后端之间的事件处理。

这些改动可能并非必须,但肯定能够大幅改善 web 应用转换的效果,让转换后的应用更像一个原生应用。这就是我从 Pake 源码中学到的知识。

Top