得物商家客服从Electron迁移到Tauri的技术实践

一、背景

得物商家客服采用的是桌面端应用表现形式,而桌面端应用主要架构形式就是一套和操作系统交互的“后端” + 一套呈现界面的“前端(渲染层)”。而桌面端技术又可以根据渲染层的不同核心划分为以下几类:

  • C语言家族:原生开发、QT
  • Chromium家族:NW、Electron、CEF
  • Webview 家族:Tauri、pywebview、webview_java
  • 自立山头:Flutter

在2022年5月份左右,得物商家客服开始投入桌面端应用业务,其目标是一个可以适配多操作系统(MacOS、Windows)、快速迭代、富交互的产品。

考虑到以上前提,我们当时可以选择的框架是Chromium家族或者Webview家族。但是当时对于Webview来说,Tauri 还并不成熟(在 2022年6月才发布了1.0版本)生态也不够丰富。对于pywebview和webview_java相对于前端来说,一方面门槛较高,另一方面生态也非常少。所以,在当时,我们选择了Chromium家族中的Electron框架。这是因为对于CEF、Electron、NW来说,Electron有着对前端开发非常友好的技术栈,仅使用JavaScript就可以完成和操作系统的交互以及交互视觉的编写,另外,Electron的社区活跃度和生态相对于其他两者也有非常大的优势。最重要的是:真的很快!

但是,随着时间的推移,直到2024年的今天,商家客服的入驻量和使用用户越来越多,用户的电脑配置也是参差不齐,Electron的弊端开始显现:

  • 性能方面:随着商家客服入驻数量的快速增加,现有Electron桌面应用在多账户+多会话高并发场景下,占用内存特别大,存在性能瓶颈;
  • 安全方面:Electron在内存安全性、跨平台攻击、不受限制的上下文和依赖管理等方面存在一些潜在的弱点;
  • 体验方面:现有Electron桌面应用包体积大,下载、更新成本较高;
  • 信息集成方面:商家客服目前需要在商家后台、商家客服后台、商家客服工作台3个系统来回切换操作,使用成本很高。

我们也发现,之前调研过的Tauri作为后起之秀,其生态和稳定性在今天已经变得非常出色,我们熟知的以下应用都是基于Tauri开发,涵盖:游戏、工具、聊天、金融等等领域:

  • ChatBox:https://github.com/Bin-Huang/chatbox 20k+ star
  • ChatGPT 桌面端:https://github.com/lencx/ChatGPT 51k+ star
  • Clash Verge:https://github.com/clash-verge-rev/clash-verge-rev 28k+ star

除此之外,因为Tauri是基于操作系统自带的Webview + Rust的框架。首先,因为不用打包一个Chromium,所以包体积非常的小:

其次Rust作为一门系统级编程语言,具有以下特点:

  • 内存安全:Rust通过所有权和借用机制,在编译时检查内存访问的安全性,避免了常见的内存安全问题,如空指针引用、数据竞争等;
  • 零成本抽象:Rust提供了丰富的抽象机制,如结构体、枚举、泛型等,但不引入运行时开销。这意味着开发者可以享受高级语言的便利性,同时保持接近底层语言的性能;
  • 并发性能:Rust内置支持并发和异步编程,通过轻量级的线程(称为任务)和异步函数(称为异步任务)来实现高效的并发处理。Rust的并发模型保证了线程安全和数据竞争的检查,以及高性能的任务调度和通信机制;
  • 可靠性和可维护性:Rust强调代码的可读性、可维护性和可靠性。它鼓励使用清晰的命名和良好的代码结构,以及提供丰富的工具和生态系统来支持代码质量和测试覆盖率;

Rust的这些额外的特性使其成为改善桌面应用程序性能和安全性的理想选择。

二、技术调研

要实现Electron迁移到Tauri,得先分别了解Electron和Tauri的核心功能和架构模型,只有了解了这些,才能对整体的迁移成本做一个把控。

2.1 Electron的核心模块

基础架构

首先来看看Electron的基础架构模型:Electron继承了来自Chromium的多进程架构,Chromium始于其主进程。从主进程可以派生出渲染进程。渲染进程与浏览器窗口是一个意思。主进程保存着对渲染进程的引用,并且可以根据需要创建/删除渲染器进程。

每个Electron的应用程序都有一个主入口文件,它所在的进程被称为 主进程(Main Process)。而主进程中创建的窗体都有自己运行的进程,称为渲染进程(Renderer Process)。每个Electron的应用程序有且仅有一个主进程,但可以有多个渲染进程。

应用构建打包

打包一个Electron应用程序简单来说就是通过构建工具创建一个桌面安装程序(.dmg、.exe、.deb 等)。在Electron早期作为 Atom 编辑器的一部分时,应用程序开发者通常通过手动编辑Electron二进制文件来为应用程序做分发准备。随着时间的推移,Electron社区构建了丰富的工具生态系统,用于处理Electron应用程序的各种分发任务,其中包括:

  • 应用程序打包https://github.com/electron/packager
  • 代码签名,例如https://github.com/electron/osx-sign
  • 创建特定平台的安装程序,例如https://github.com/electron/windows-installer或https://github.com/electron-userland/electron-installer-dmg
  • 本地Node.js原生扩展模块重新构建https://github.com/electron/rebuild
  • 通用MacOS构建https://github.com/electron/universal

这样,应用程序开发者在开发Electron应用时,为了构建出跨平台的桌面端应用,不得不去了解每个包的功能并需要将这些功能进行组合构建,这对新手而言过于复杂,无疑是劝退的。

所以,基于以上背景,目前使用的比较多的是社区提供的Electron Builder(https://github.com/electron-userland/electron-builder)一体化打包解决方案。得物商家客服也是采用的上述方案。

应用签名&更新

现在绝大多数的应用签名都采用了签名狗的应用签名方式,而我们的商家客服桌面端应用也是类似,Electron Builder提供了一个sign的钩子配置,可以帮助我们来实现对应用代码的签名:

...
    "win": {
      "target": "nsis",
      "sign": "./sign.js"
    },
...

(详细的可以直接阅读electron builder官网介绍,这里只做简单说明)

对于应用更新而言,我们之前采用的是electron-updater自动更新模式:

如果对这块感兴趣,可以阅读我们之前的文章:https://juejin.cn/post/7195447709904404536?searchId=202408131832375B6C2C76DEEE740762EA

2.2 Tauri的核心模块

基础架构

那么,Tauri的基础架构模型是什么样的?其实官网对这块的介绍比较有限,但是我们可以通过其源码仓库和代码结构管中窥豹的了解Tauri的核心架构模型,为了方便大家理解,我们以得物商家客服桌面端应用为模型,简单的画了一个草图:

一些核心模块的解释:

WRY

由于Web技术具有表现力强和开发成本低的特点,与 Electron 和NW等框架类似,Tauri应用程序的前端实现是使用Web技术栈编写的。那么Tauri是如何解决Electron/CEF等框架遇到的Chromium内核体积过大的问题呢?

也许你会想,如果每个应用程序都需要打包浏览器内核以实现Web页面的渲染,那么只要所有应用程序共享相同的内核,这样在分发应用程序时就无需打包浏览器内核,只需打包Web页面资源。

WRY是Tauri的封装Webview框架,它在不同的操作系统平台上封装了系统的Webview实现:MacOS上使用WebKit.WKWebview,Windows上使用Webview2,Linux上使用WebKitGTK。这样,在运行Tauri应用程序时,直接使用系统的Webview来渲染应用程序的前端展示。

TAO

跨平台应用窗口创建库,使用Rust编写,支持Windows、MacOS、Linux、iOS和Android等所有主要平台。该库是winit的一个分支,Tauri根据自己的需求进行了扩展,如菜单栏和系统托盘功能。

JS API

这个API是一个JS库,提供调用Tauri Rust后端的一些API能力,利用这个库可以很方便的完成和Tauri Rust后端的交互以及通信。

看起来有点复杂,其实核心也是分成了主进程和渲染进程两个部分。

  • Tauri的主进程使用Rust编写,Tauri在主进程中提供了一些常用的Rust API比如窗口创建、消息提醒... 如果我们觉得主进程提供的API不够,那么我们可以通过Tauri的插件体系自行扩展。
  • Tauri的渲染进程则是运行在操作系统的Webview当中的,我们可以直接通过JS + HTML + CSS来编写,同时,Tauri会为渲染进程注入一些全局的JS API函数。比如fs、path、shell等等。

Tauri

这是将所有组件拼到一起的crate。它将运行时、宏、实用程序和API集成为一款最终产品

应用构建打包

Tauri提供了一个CLI工具:https://v1.tauri.app/zh-cn/v1/api/cli/,通过这个CLI工具的一个命令,我们可以直接将应用程序打包成目标产物:

yarn tauri build

此命令会将渲染进程的Web资源 与 主进程的Rust代码一起嵌入到一个单独的二进制文件中。二进制文件本身将位于src-tauri/target/release/[应用程序名称],而安装程序将位于src-tauri/target/release/bundle/。

第一次运行此命令需要一些时间来收集Rust包并构建所有内容,但在随后的运行中,它只需要重新构建您的应用程序代码,速度要快得多。

应用签名&更新

Tauri的签名和Electron类似,如果需要自定义签名钩子方法,在Tauri中现在也是支持的:

{
   "signCommand": "signtool.exe --host xxxx %1"
}

后面我们会详细介绍该能力的使用方式。

而对于更新而言,Tauri则有自己的一套体系:Updater | Tauri Apps这里还是和Electron有着一定的区别。

2.3 选型总结

通过上面的架构模型对比,我们可以很直观的感受到如果要将我们的Electron应用迁移到Tauri上,整体的迁移改造工作可以总结成以下图所示:

核心内容就变成了以下四部分内容:

  • 主进程的迁移:而对于商家客服来说,目前主要用的有:
  • 自定义窗口
  • autoUpdater自动更新
  • BrowserWindow窗口创建
  • Notification消息通知
  • Tray系统托盘
  • IPC通信

而这些API在Tauri中都有对应的实现,所以整体来看,迁移成本和技术可行性都是可控的。

  • 渲染进程的迁移:渲染进程改造相对而言就少很多了,因为Tauri和Electron都可以直接使用前端框架来编写渲染层代码,所以几乎可以将之前的前端代码直接平移过来。但是还是有一些小细节需要注意,比如IPC通信、JS API的改变、兼容性... 这部分后面也会详细介绍。
  • 应用构建打包:从之前的Electron构建模式改成Tauri构建模式,并自动化整个构建流程和链路。
  • 应用签名&更新:签名形式不用改,主要需要调整签名的配置,实现对Tauri应用的自动签名和自动更新能力。

最终,我们选择了Tauri对现有的商家客服桌面端进行架构优化升级。

三、技术实现

3.1 渲染进程代码迁移

目录结构调整

在聊如何调整Tauri目录结构之前,我们需要先来了解一下之前的Electron应用目录结构设置,一个最简单的Electron应用的目录结构大致如下:

.
├── index.html
├── main.js
├── renderer.js
├── preload.js
└── package.json

其中文件说明如下:

  • index.html:渲染进程的入口HTML文件。
  • renderer.js:渲染进程的入口JS文件。
  • main.js:主进程入口文件
  • preload.js:预加载脚本文件
  • package.json:包的描述信息,依赖信息

有的时候你可能需要划分目录来编写不同功能的代码,但是,不管功能目录怎么改,最终的渲染进程和主进程的构建产物都是期望符合类似于上面的结构。

所以,之前得物的商家客服也是类似形式的目录结构:

.
├── app              // 主进程代码目录
├── renderer-process // 渲染进程代码目录
├── ...              // 一些其他配置文件,vite 构建文件等等
└── package.json

对于Tauri来说,Tauri打包依托于两个部分,首先是对前端页面的构建,这块可以根据业务需要和框架选择(Vue、 React)进行构建脚本的执行。一般前端构建的产物都是一个dist文件包。

然后是Tauri后端程序部分的构建,这块主要是对Rust代码进行编译成binary crate。

(Tauri后端的编译在很大程度上依赖于操作系统原生库和工具链,因此当前无法进行有意义的交叉编译。所以,在本地编译我们通常需要准备一台mac和一台Windows电脑,以满足在这两个平台上的构建。)

整体来看,和Electron是差不多的,这里,我们就直接使用了官方提供的create-tauri-app(https://github.com/tauri-apps/create-tauri-app)脚手架来创建项目,其目录结构大致如下:

.
├── src              // 渲染进程代码
├── src-tauri        // Rust 后端代码
├── ...              // 一些其他配置文件,vite 构建文件等等
└── package.json

所以,这里对渲染进程的目录调整就很清晰了,直接将我们之前Electron中的renderer-process目录中的代码迁移到src目录中即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值