最近抽出了不少业余时间来开发一个新的项目Storm(一个使用 Solid.js 和 Tauri 开发的跨平台 Rest 客户端),简单记录一下开发过程。
作为一个后端开发,免不了遇到测试 http 接口的场景。这个领域最成熟的应用当然是 Postman,近期也有一些国产替代品出现,比如Apifox。
这些应用都是基于 Electron 开发的,但本人十分抗拒在电脑上安装除了 VS Code 之外的第二个 Electron 应用(出于 Electron 应用的体积、启动速度和内存占用的缘故)。
我现在一般使用 VS Code 的Thunder Client插件进行接口测试,在大部分简单场景下已经足够用了。
趁着近期想认真学习实践一下 solid.js 的契机,我决定用 solid.js 和 tauri 开发一个 Rest 客户端。
以下数据均为 Windows 11 64 位系统下的安装包体积。
应用 | 框架 | 安装包体积(MB) |
---|---|---|
Postman | Electron | 160 |
Apifox | Electron | 129 |
Storm | Tauri | 2.7 |
编译后的 js 只有 32KB。 作为对比,cdn 上直接引入 react-dom.production.min.js 就需要 128KB。
使用 JSX 语法定义组件还是很方便的,并且 solid.js 提供了很多内置的组件,比如<For>
、<Show>
、<Switch>
等,可以很方便地实现循环、条件渲染等功能。
solid.js 中的 signal 可以定义在任何地方,不用和具体的组件绑定,天生就是 MVVM 架构。
例如可以分别定义了一个 url signal 和一个 queries signal 用于表示请求的 url 与 query 参数。
export const [url, setUrl] = createSignal<string>("https://httpbin.org/get");
export const [queries, setQueries] = createSignal<Query[]>([
{ key: "", value: "" },
]);
定义一个 queryString(使用 createMemo),当 queries 变化时,queryString 也会自动更新。
const queryString = createMemo(() => {
const params = new URLSearchParams();
queries().forEach((query) => {
query.key.length > 0 && params.append(query.key, query.value);
});
return params.toString();
});
最后定义一个 realURL,当 url 或者 queryString 变化时,realURL 也会自动更新。最终发起请求时,只需要使用 realURL() 即可。
export const realUrl = createMemo(() => {
if (queryString().length === 0) return url();
return url() + "?" + queryString();
});
我最初是使用 fetch API 来发起请求的,但是遇到了跨域问题,经过调研后使用了 Tauri 提供的原生 HTTP API。
import { fetch } from "@tauri-apps/api/http";
export async function doRequest() {
setLoading(true);
setError("");
setResponse(defaultResponse);
console.log(realUrl(), method(), requestHeaders(), requestForm(), body());
const record = {
method: method(),
url: url(),
headers: headers(),
queries: queries(),
formItems: formItems(),
body: body(),
ts: Date.now(),
};
await storage.appendRequestRecord(record);
setHistory((history) => [record, ...history.slice(0, 19)]);
try {
const start = Date.now();
const response = await fetch<number[]>(realUrl(), {
method: method(),
headers: requestHeaders(),
body: method() === Method.GET ? undefined : requestBody(),
responseType: ResponseType.Binary,
});
setResponse({
status: response.status,
headers: response.headers,
body: new Uint8Array(response.data).buffer,
time: Date.now() - start,
});
} catch (error) {
setError((error as any).toString());
} finally {
setLoading(false);
}
}
趁热打铁,我还是用了 Tauri 提供的其他原生 API,包括利用文件系统接口实现一个简单的请求历史记录、利用剪贴板接口实现复制请求结果等功能。
Tauri 提供的所有原生 API 都需要进行相关配置才能正常使用(修改src-tauri\tauri.conf.json
的 allowlist),基本上参考官方文档就可以了。
不过我还是遇到了一个坑,在 Windows 环境下,配置读取用户目录的权限只需要简单的通配符就可以了。
{
"tauri": {
"allowlist": {
"fs": {
"all": true,
"scope": ["$HOME/**"]
}
}
}
}
但是在 ubuntu 编译运行应用的时候,会遇到没有对应路径的权限的报错。经过在互联网上查询后,发现 tauri 的文件权限在 linux 下需要非常细致的定义。
{
"tauri": {
"allowlist": {
"fs": {
"all": true,
"scope": [
"$HOME/.storm",
"$HOME/.storm/history",
"$HOME/.storm/history/history.json"
]
}
}
}
}
使用 solid.js 和 tauri 进行跨平台桌面应用的开发体验还是相当不错的,构建出的应用在体积、内存占用、启动时间上的表现也都很优秀。