初次体验Tauri和Sycamore(1)

原创作者:庄晓立(LIIGO)
原创时间:2024年11月10日
原创链接:https://blog.csdn.net/liigo/article/details/143666827
版权所有,转载请注明出处。

tauri-splash

前言

Tauri 2.0发布于2024年10月2日,Sycamore 0.9发布于2024年11月1日。二者在近期双双发布重大版本升级,是我(LIIGO)本次想体验他们的主要动机。Tauri自2022年发布v1.0之后就早已火出天际,而Sycamore自2022发布v0.8之后沉寂了两年之久,如今各自凤凰涅槃,他们的组合体会擦出怎样的火花?

关于Tauri

Tarui用于创建小巧、快速、安全、跨平台的桌面GUI应用和移动应用软件。

Create small, fast, secure, cross-platform applications.

Tauri APP主要由三个子系统组成,Webview + Shell + Rust。其中Webview是前端WEB载体,用于展现UI与用户交互;Shell是Webview的载体,提供窗口/菜单/通知等OS级支撑;Rust是后端核心,为前端提供功能支撑和运行时支撑。前端WebUI + 后端Rust业务逻辑,整合了WEB在布局和UI的优势以及Rust后端功能性能优势,是颇具竞争力的跨平台GUI应用开发模式,且已被Electron和Tauri实证有效。在Rust编程领域,主流NativeUI框架稀缺或生态不成熟,主动拥抱生态极其丰富的JS/TS前端框架是明智之举。

为什么需要Rust在后端提供功能支撑呢?因为前端App运行在Webview中,那是沙箱环境,其功能受限(例如不能启动OS进程/执行CLI),因而需要寻求拓展外界支持。对于Electron而言,由Nodejs提供后端支撑;对于Tauri而言,由Rust提供后端支撑。这也是Tauri和Electron的本质区别。区别的本质是不同程序员群体做出的不同倾向性选择:Rust程序员倾向于选择Rust,JS/TS程序员倾向于选择Nodejs。Tauri的核心运行时库也被编译进后端子系统,跟Tauri App的后端业务逻辑代码处于同一Crate。

Tauri 2.0开始引入插件(Plugins)生态,并且预置了一批立等可取的插件,可视为对后端的拓展,缓解了对后端的强依赖,对非Rust开发者更是福音。它的插件往往是跨桌面系统(Windows/Linux/macOS)和移动系统(Android/iOS)提供统一的接口。除了官方插件外,还有第三方插件可供选择。

抛开后端再看Webview,Tauri和Electron还有一个重大区别:Electron App内嵌携带Webview即Chromium;而Tauri App不携带Webview,它直接使用App用户OS里的Webview(Windows内的WebView2,macOS内的WKWebView,Linux内的webkit2gtk)。Electron的优势是Webview已知、确认与App兼容,劣势是App尺寸过大(上百MB)。Tauri的优势是App尺寸很小(十余MB),劣势是Webview未知、与App兼容性未知。此处Tauri的劣势是可控的、可接受的,理由如下:1) 各主流平台的Webview已经逐渐趋同(用现代的或相同的浏览器内核);2) Tauri为App生成的安装程序(Installer)会协助用户获取兼容Webview;3) WEB前端App原本就不应该使用厂商专用特性。4) 做网站也是要面对不同的Webview的,该踩得坑全球网友都帮你已经踩过了。

作为Tauri App的开发者,你没法选Webview(由目标用户的操作系统而定),也没法选后端语言(确定使用Rust语言),但你可以自由的选择前端框架(取决于你个人或团队的习惯和偏爱)。类似于Electron,Tauri也支持多种主流前端框架,如React、Vue、Svelte、Solid、Angular、Preact等等。Tauri不仅支持前述JS/TS前端,还支持WASM前端,如Yew、Leptos、Sycamore、Dioxus等(Rust语言),以及.Net的Blazor前端(C#语言)。当然你也可以不用任何框架(Vanilla,纯JavaScript/CSS/HTML)。

创建App

Tauri使用两个命令行工具 (create-tauri-app, tauri-cli) 创建和编译打包App。首先要安装这两个CLI:

cargo install create-tauri-app --locked
cargo install tauri-cli --version "^2.0.0" --locked

create-tauri-app, tauri-cli 从Rust源码编译(cargo install)都相当耗时(均依赖数百个crates)。我还是建议自行下载编译后版本放到cargo bin目录。我给他们提了建议,今后会推荐使用 cargo binstall 下载编译好的二进制CLI,而不是使用cargo install从源码开始编译。

这两个CLI也有都对应的npm包:create-tauri-app, @tauri-apps/cli,二者都是间接调用Rust编译好的可执行文件。供TS/JS前端使用。

执行如下命令开始创建Tauri app:cargo create-tauri-app。CLI会逐步引导你输入或选择如下信息:

  • 项目名称(Project name),默认是"tauri-app"
  • Identifier 默认是"com.tauri-app.app"
  • 前端语言,可选 Rust, TS/JS, .Net
  • UI模板,视前端语言而定
    • Rust UI模板:可选 Vanilla, Yew, Leptos, Sycamore, Dioxus
    • TS/JS UI模板:可选 Vanilla, Vue, Svelte, React, Solid, Angular, Preact
    • .Net UI模板:可选 Blazor

选TS/JS的UI模板前还需要选择包管理器:pnpm, yarn, npm, deno, bun

因为这次我(Liigo)想体验Tauri+Sycamore,因而前端语言选Rust,UI模板选Sycamore。

目录结构

Tauri+Sycamore App目录结构:

├─ public/
├─ src/
│  ├─ app.rs
│  └─ main.crs
├─ src-tauri/
│  ├─ ...
│  ├─ Cargo.toml
│  └─ tauri.conf.json
├─ .gitignore
├─ .taurignore
├─ Cargo.toml
├─ index.html
├─ README.md
├─ styles.css
└─ Trunk.toml

Tauri源码目录对前端和后端代码进行了隔离。后端代码使用src-tauri/子目录;前端代码使用除此之外的其他文件和子目录。

编译打包

开发版

cargo tauri dev

编译完成后自动启动App,弹出GUI主窗口。允许开发者在App运行过程中修改前端源代码,Tauri(或者说Trunk)会自动编译,并刷新App窗口内容,但是App并不会中途退出或重启(原理:Trunk通过WebSocket向开发版App推送重新加载UI的指令;Dioxus虽然没用Trunk但也实现了类似机制)。

它会检查Trunk是否存在,不存在的话会自动下载源码并编译。但是在Windows下编译Trunk很可能会碰到如下问题(间接依赖openssl开发者库):

  It looks like you're compiling for MSVC but we couldn't detect an OpenSSLinstallation. If there isn't one installed then you can try the rust-opensslREADME for more information about how to download precompiled binaries ofOpenSSL:https://github.com/sfackler/rust-openssl#windowsnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: failed to compile `trunk v0.21.2`, intermediate artifacts can be found at `E:\tmp\RUST_DIR\CARGO_TARGET_DIR`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

我找到的解决办法是,去github的trunk官方仓库下载编译好的trunk.exe,丢进cargo bin目录即可(或任意PATH目录均可)。

如果cargo tauri dev过程中看到如下提示时只需耐心等待:

Warn Waiting for your frontend dev server to start on http://localhost:1420/…

这是因为Trunk先启动了(WEB服务监听1420端口),等待APP主动连接。但是编译App需要时间,等它编译完并启动后才能连上。

通过App窗口右键菜单可以打开devtools。在App运行过程中,还可以在浏览器中打开 http://localhost:1420/ ,网页内容跟GUI窗口是一样的(可视为App的另一个实例)。

发行版

cargo tauri build

编译App并打包为安装包。

如果编译过程中提示正在下载Wix但失败(Github国内连接不稳定):

Downloading https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip

你可以通过其他方法手动下载此连接,解压到如下目录:C:\Users\liigo\AppData\Local\tauri\WixTools314\(里面有一堆exe等文件)。

此方法是我(LIIGO)从 Tauri仓库源码 里扒出来的。实证管用。

同理,如果NSIS也下载不了,可以用类似的办法手动下载解压到目录C:\Users\liigo\AppData\Local\tauri\NSIS。但是我没用这个方法。因为我觉得既然已经有Wix用来生成MSI安装包,就没必要再下载NSIS(生成另一种安装包)。

我研究了一下,将配置文件tauri.conf.json里面的bundle.targets改为"msi"(原来是"all")即可禁用NSIS等。

文件大小

Tauri+Sycamore app编译后是一个可独立运行的图形用户界面(GUI)exe,其内部整合了wasm/css/图片等文件,没有其他外部依赖。exe文件大小是10.3MB,对应的安装包msi文件大小是3.6MB(安装后也只有那个exe和一个用于卸载的快捷方式文件(指向系统文件msiexec.exe /x))。sycamore生成的wasm文件大小为750KB(已包含在exe中)。App启动时有大约一两秒的窗口白屏。

作为对比,再看一下Tauri+Dioxus app的数据:exe大小10.6MB,mis大小3.9MB,wasm文件大小为1.3MB(debug版33MB或25MB),也有一两秒的启动白屏。大同小异吧。我(LIIGO)暂且认为这是Tauri App (Hello world)的平均水平。

这样的文件大小应该很香吧。最起码比Electron app香多了。

1MB的wasm文件,用在普通网站上,网络传输加载延迟是一个较大的负担,但是对Tauri app而言这就是本地加载啊,性能没得说。

资源占用

Tauri+Sycamore app启动后,内部加载3到6个Webview2进程,连同exe合计占用内存60到90MB。

无操作时CPU占用率为0%;在app窗口上移动鼠标时,CPU占用率逐步上升到10%甚至更多。这个问题是不是需要改善呀。

命令(Commands)

前端可以调用后端定义的Command。反之则不行,因为只有后端有Command,前端没有。

TS/JS前端调用Command

Tauri给前端提供了调用后端Command的通用接口,invoke函数:

import { invoke } from '@tauri-apps/api/core';
const result = invoke('greet', 'liigo'); // 调用后端greet命令并接收返回值

@tauri-apps/api是Tauri发布到npm的多个package之一,可供Tauri所有TS/JS前端框架使用。

示例greet是在后端Rust代码中自定义的Command(有参数有返回值):

#[tauri::command]
fn greet(name: &str) -> String {format!("Hello, {}! You've been greeted from Rust!", name)
}

注意:新增Command后需要同步更新lib.rs文件内的tauri::generate_handler![greet]调用。

前端调用后端,本质是进程间通讯(IPC),invoke()底层利用的是各Webview的专有实现,例如window.chrome.webview.postMessage()

Rust前端调用Command

但是,我现在用的是Rust前端啊,@tauri-apps/api用不上啊。

没关系,Tauri还通过另一种方式为前端提供接口:window.__TAURI__,大致等效于@tauri-apps/api。此接口存在的前提是事先修改tauri.conf.json文件配置app.withGlobalTauritrue

于是,invoke函数就在这里:window.__TAURI__.core.invoke。Rust前端和TS/JS前端都能使用。

调用实例:

#[wasm_bindgen]
extern "C" {#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}#[derive(Serialize, Deserialize)]
struct GreetArgs<'a> {name: &'a str,
}let name = "liigo";
let args = serde_wasm_bindgen::to_value(&GreetArgs { name }).unwrap();
let new_msg = invoke("greet", args).await.as_string().unwrap();

可以看出,从Rust前端调用Rust后端,反而比TS/JS更麻烦。麻烦的点是:

  • 需要借助#[wasm_bindgen]声明invoke函数
  • 需要定义被调用command的参数struct并支持序列化
  • Command的参数值需要先转换为JsValue类型才能传入invoke函数
  • invoke返回值是JsValue类型,还要转换类型才能使用

我想这可能是大伙儿不愿意在Tauri中使用Rust前端的原因之一。不知道后续能不能改善。现阶段还是使用TS/JS前端更有生产力,生态也更成熟。

题外话:Rust前端调用Rust后端?都是Rust,代码直接写在前端是不是就不用调用后端了?你想多了。Rust前端是被编译成WASM、在Webview沙箱环境中执行的,其功能也是受限的,有时候不可避免依赖Rust后端。

事件(Events)

前端可以给后端发送事件,后端也可以给前端发送事件。

前端给后端发送Event

TS/JS前端使用@tauri-apps/api package 内的emit()函数给后端发送Event。

import { emit } from '@tauri-apps/api/event';
await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });

emit()实际上只是对invoke()的简单封装:

async function emit(event, payload) {await invoke('plugin:event|emit', { event, payload });
}

(上述invoke调用中的'plugin:event|emit'似乎暗示event也是一个插件?我研究后发现的确如此。)

Rust前端给后端发送Event,比照前文调用window.__TAURI__.event.emit()window.__TAURI__.core.invoke()

后端给前端发送Event

使用 tauri crate:

  • tauri::AppHandle::emit
  • tauri::App::emit
  • tauri::webview::WebviewWindow::emit
  • tauri::webview::Webview::emit
  • tauri::window::Window::emit

例如:

use tauri::Emitter;#[tauri::command]
fn synchronize(window: tauri::Window) {window.emit("synchronized", ());
}

Rust前端如何获取tauri::Window对象呢?我估计是比照前文调用window.__TAURI__.window.getCurrentWindow()

通道(Channels)

通道用于在前后端之间快速双向传输大块数据、流数据,传输是有序的,先发先到。

通道在前端的JavaScript类型是@tauri-apps/api/core/Channel,位于@tauri-apps/api package内;通道在后端的Rust类型是tauri::ipc::Channel,位于tauri crate内。以上二者是Channel的一体两面,同一个Channel对象,在前端的表现为JS Channel,在后端表现为Rust Channel。

应用示例:https://tauri.app/develop/calling-frontend/#channels

插件(Plugins)

前端和后端都可以调用插件。

Tauri插件本身就是Rust的crate(例如tauri-plugin-dialog),在后端Rust代码中调用插件,跟调用其他crate一样,直接cargo add就OK了。

每个插件都有对应的npm包(例如@tauri-apps/plugin-dialog)提供TS/JS接口(通常是自动化生成),供TS/JS前端调用。如果是Rust前端呢,大概要麻烦一些,参考前端调用Command。

前面用于调用Command的invoke()函数也具备调用插件的功能,调用语法是:invoke('plugin:插件名|函数名', { 参数 })

插件的TS/JS接口实际上也只是对invoke()的简单封装,例如:

async function open(options = {}) {if (typeof options === 'object') {Object.freeze(options);}return await invoke('plugin:dialog|open', { options });
}

总结

近两年来Tauri受到大量关注,其Github仓库STAR已高达84.7K,已经逐渐逼近Electron的114K。
它不仅吸引了许多Rust用户,还有很多前端非Rust用户尝试用它开发跨平台桌面应用程序。
可以预见Tauri 2.0之后会有越来越多的开发者用它开发跨平台移动应用APP。

我虽然也一直观望着Tauri的开发进展,但沉下心来仔细体验它还是头一次。今日借此机会,大致介绍了它的功能特点,初步总结了它的基础用法,希望对感兴趣的朋友们有帮助。

感觉TS/JS前端与Tauri后端的结合更妥帖,使用更方便,生态更好。Rust前端与Tauri后端之间交互较为麻烦,尚需继续打磨。

关于标题中提到的Sycamore相关体验,我会发布在后面的文章中,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/10961.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于Spring Boot+Vue的学院食材采供管理系统

一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17 前端&#xff1a; 技术&#xff1a;框架Vue.js&#xff1b;UI库&#xff1a;ElementUI&#xff1b; 开发工具&…

【C++】vector模拟实现、迭代器失效问题(超详解)

vector会使用之后我们来模拟实现一下&#xff0c;通过对vector的模拟实现&#xff0c;我们来说一下迭代器失效问题。 1.准备工作 在头文件vector.h里声明和实现函数&#xff0c;然后在test.cpp里测试代码的正确性。 在vector.h中用命名空间分隔一下&#xff0c;因为c库里面也有…

基于SpringBoot的渔具管理系统【附源码】

基于SpringBoot的渔具管理系统 效果如下&#xff1a; 系统主页面 系统登陆页面 管理员主页面 用户管理页面 渔具信息管理页面 租赁信息管理页面 归还信息管理页面 渔具信息页面 用户登陆页面 个人中心页面 研究背景 随着社会的发展&#xff0c;渔具销售企业之间的竞争与合作…

string

文章目录 一. STL1.概念2.版本 二. string类2.1 为什么学习string类2. 标准库中的string类2.2.1 构造&#xff08;7个&#xff09;2.2.2 对string类对象进行访问和修改&#xff08;1&#xff09;operator[]&#xff08;2&#xff09;迭代器1.迭代器的使用2.迭代器的价值&#x…

B2B订货系统功能设计与代码开发(PHP + MySQL)

在B2B&#xff08;Business to Business&#xff09;电子商务中&#xff0c;企业之间的商品订购、交易和供应链管理是核心功能。一个高效的B2B订货系统可以帮助企业管理库存、订单、采购等业务流程。本文将介绍一个基于PHP与MySQL技术栈的B2B订货系统的功能设计与开发流程。 一…

【2024】前端学习笔记17-Vue初体验

学习笔记 1.什么是vue2.vue初体验3.代码拆分释义4.本文新内容1.什么是vue Vue是一个用于构建用户界面的渐进式JavaScript框架。 它专注于视图层,易于集成或与现有项目结合使用,也可以通过其生态系统实现更复杂的单页应用(SPA)。 Vue的核心特点包括响应式数据绑定、组件化开…

java动态代理

静态代理和动态代理 1、代理模式2、静态代理2.1 定义接口2.2 被代理对象实现2.3 代理对象2.4 客户端 3、JDK动态代理3.1 JDK动态代理例子3.1.1 定义接口3.1.2 被代理对象实现3.1.3 实现InvocationHandler接口3.1.4 创建代理对象 3.2 动态代理底层原理3.3 查看生成的代理类 4、C…

多线程的创建方式以及及Thread类详解

目录 一.线程的创建方法&#xff1a;&#xff08;重点&#xff09; 一&#xff1a;继承Thread类 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 二.实现Runnable接口 写法一&#xff1a;正常写法 写法二&#xff1a;匿名内部类 三. 实现 Callable 接口 ​…

408最后冲刺阶段,怎么做题才能考到120+?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重要性排序如下&#xff1a;真题占据首位&#xff0c;紧随其后的是王道模拟题&#xff0c;王道书与题目则紧随其后&#xff0c;而408统考配套习题&#xff08;高教版&#xff09;与之大致相当。 真题&#xff0c;无疑…

如何对接低价又稳定的影视会员渠道?

对接低价折扣影视会员渠道通常涉及到与影视内容提供商或第三方分销商的合作。以下是一些基本步骤和注意事项&#xff0c;帮助你顺利对接这类渠道&#xff1a; 1. 市场调研 了解市场&#xff1a;研究市场上现有的影视会员服务提供商&#xff0c;包括价格、服务、用户反馈等。确…

crond 任务调度 (Linux相关指令:crontab)

相关视频链接 crontab 进行 定时任务 的设置 概述 任务调度&#xff1a;是指系统在某个时间执行的特定的命令或程序 任务调度的分类&#xff1a; 1.系统工作&#xff1a;有些重要的工作必须周而复始地执行。如病毒扫描等。 2.个别用户可能希望执行某些程序&#xff0c;比如…

顺序表+ArrayList

文章目录 一、基础知识1.1 数据结构类的继承图1.2 List 介绍1.3 线性表 二、数据结构 -- 顺序表2.1 什么是顺序表以及优缺点2.2 用数组实现顺序表细节解析代码 三、ArrayList3.1 Java中如何使用ArrayList3.2 ArrayList源码无参构造方法add方法扩容方法指定初始容量构造利用其他…

【工具变量】排污权交易政策试点DID(2000-2023)

数据简介&#xff1a;在过去几十年间的“高增长、高能耗、高污染”的经济发展背景下&#xff0c;随着社会各界不断反应高经济增长背后付出的巨大环境代价&#xff0c;中国ZF将节能环保减排纳入长期规划治理中。在2007年&#xff0c;我国开始启动了二氧化硫&#xff08;SO2&…

通用特效Shader

一、通用特效Shader介绍 1.1 什么是通用特效材质 Unity支持SRP Batcher后&#xff0c;使用UberShader的优势非常明显。所谓&#xff0c;UberShader&#xff0c;即一个超级Shader&#xff0c;覆盖一类功能&#xff0c;而不是多个分散的小Shader&#xff0c;比如一个通用特效Sh…

网络安全SQL初步注入2

六.报错注入 mysql函数 updatexml(1,xpath语法,0) xpath语法常用concat拼接 例如: concat(07e,(查询语句),07e) select table_name from information_schema.tables limit 0,1 七.宽字节注入(如果后台数据库的编码为GBK) url编码:为了防止提交的数据和url中的一些有特殊意…

Golang--面向对象

Golang语言面向对象编程说明&#xff1a; Golang也支持面向对象编程(OOP)&#xff0c;但是和传统的面向对象编程有区别&#xff0c;并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性是比较准确的。Golang没有类(class)&#xff0c;Go语言的结构体(struct)和其…

英国留学论文写作中复合句式基础知识讲解

从句子的结构出发&#xff0c;复合句式是将两个以上的独立、完整的字句子通过coordinating conjunction或者分号连接在一起。因此&#xff0c;复合句式可以理解成为两个以上的简单句子组合在一起。下面英国翰思教育通过举例的方式&#xff0c;来介绍如何将独立的句子连接在一起…

从奇富科技,QQ钱包看信贷服务、贷款超市的的客户注册认证流程有什么不同

概览 奇富科技作为港股信贷第一企业&#xff0c;目前已服务2.4亿用户&#xff0c;是国内头部信贷科技服务平台。 QQ钱包&#xff0c;作为8亿用户的贷款超市&#xff0c;拥有其他贷款超市产品梦寐以求的流量入口。 产品模式 奇富科技作为信贷科技服务平台&#xff0c;主要提…

寻找伤感短视频素材 这些网站帮你轻松下载无水印资源

无论是制作情感类短视频&#xff0c;还是为抖音视频寻找合适的素材&#xff0c;伤感视频素材一直是创作者们关注的重点。如果你正在为如何找到高质量的伤感素材而困扰&#xff0c;那么今天我将推荐一些非常实用的素材网站&#xff0c;帮助你快速找到适合的伤感视频素材&#xf…

Java项目实战II基于Spring Boot的大学生智能消费记账系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在当今社会…