🌀

Rustの勉強がてらTauriを触ってみたら1行もRustを書かずにデスクトップアプリができた

2022/10/16に公開

いや、意味ないじゃん!
TauriTauri APIで小さいデスクトップアプリを作ったお話です。内容はあまりまとまってません。

前提

  • 筆者はガチ業務でJS/TSコードを書いているエンジニアではありません。ほぼほぼ趣味です。
  • Electronを触ったこと自体は一応ありますが、かなり昔の話ですし、Electron APIも使った事はありません。
  • タイトル通りRustは素人です。
  • 何なら文字書きもあんまり得意じゃないです…

作ったもの(宣伝)

voinaというチャットボットAPIと音声合成ソフトウェアの仲介をするアプリを作りました。パブリックでアプリケーションを公開するのはほぼ初なので、色々おかしな所があるかもしれません。

https://github.com/uboar/voina

このアプリで使用しているチャットボットAPIはりんなで有名なrinna社が公開している物ですが、なんと自作のキャラクターモデルが使えるらしく(まだ試行錯誤中)、個性がある程度確立されているVOICELOIDやVOICEVOXのキャラクターと絡めれば面白い物が出来るんじゃないか!と思い立ったのが作ったきっかけです。

rinna社のAPIについてはまた別の機会にちょっと記事を書いてみようと思います。

Tauriを選んだ目的

Rustにちょっと興味があった

STM32マイコンのプログラムをC/C++で書いていた経験があるのですが、ある時Rustでも書けるらしいという話を小耳に挟みました。
で、軽くRustについて調べたところ、

  • なんかメモリ確保と解放がうまいこと安全にできるらしい
  • なんか速いらしい(JSと比べて)
  • Webアプリから組込みまでカバーできるらしい

という事なので、機会があればちょっと勉強したいな~と思ってました。

Electronのファイルサイズがデカい

ElectronはChromiumをバンドルしてビルドする為、素のビルドでも100MB程度のサイズになります。ローカルにあるファイルをちょいちょい弄る程度の簡素で小規模なアプリをかなり昔Electronで作った事があるのですが、ファイルサイズが大きい事が不評でした。

TauriはOSのWebView機能を用いる為、ファイルサイズが劇的に小さくなります。
今回フロントエンドの構成はVue3+Vite+Vuetify(beta)となっていますが、ビルドサイズは8MB程です。

そもそもWebアプリじゃダメなん?という話

VOICEVOXにはWeb版とそれを使えるAPIがあるので、当初はWebアプリでのリリースを目指していたのですが、チャットボットAPI側のCORS対応が無いのと折角ならVOICELOIDやAI VOICEとも連携させたいという事で、今回はデスクトップアプリを開発する事にしました。
ちなみにUI自体はWebアプリ想定で書いた物をそのまま持ってきています。

CORSについてはService Workerを使えばなんとかなるかもしれません。

なんかTauri APIってのがあるらしいじゃん

Kumassy氏のTauri本を読みながらちまちまと開発を進めていたのですが、Tauri APIなる物があるのを知りました。

これ便利じゃね?バックエンドのコードを一々書かなくても基本的な事は出来るって事だよね?
という事で、↓↓

直下にあるconfig.jsonを読むor無ければ生成する
import { resourceDir } from '@tauri-apps/api/path'
import { readTextFile, writeTextFile, exists, BaseDirectory } from '@tauri-apps/api/fs';

export const loadConfig = async (): Promise<Config> => {
    let config = initialConfig;
    if (await exists('config.json', { dir: BaseDirectory.Resource }) as unknown) { // boolean?
        config = JSON.parse(await readTextFile('config.json', { dir: BaseDirectory.Resource })) as Config;
        console.info(`コンフィグファイルを${await resourceDir()}から読み込みました`);
    } else {
        //コンフィグファイルを生成する
        await writeTextFile('config.json', JSON.stringify(config), { dir: BaseDirectory.Resource });
        console.info(`コンフィグファイルを${await resourceDir()}に生成しました`);
    }
    return config;
}

「Webアプリでは実現出来ない事があったのでデスクトップアプリにしました」的なニーズにマッチするAPIが提供されており、これのお陰で1行もバックエンドのコードを書く事無くアプリが出来てしまいました。お陰でRustの勉強はまだ出来てませんが。

ちなみにElectron APIの存在は後から知りました。そんな事ある?

APIで出来ること(一部書き出し)

一部のみですが、APIで出来ることを軽く紹介します。

名前 機能
cli コマンドライン引数などを持ってくる事が出来ます。
dialog ファイル選択のダイアログを出せます。
event ウィンドウ中心にイベントハンドリングを提供します。
fs ローカルのファイル操作が出来ます。
globalShortcut OS側にグローバルショートカットを登録できます。
http バックエンド側のHTTPクライアントです。
notification 通知を送れます。
shell シェルスクリプトを実行出来ます。

注意すべき点は、tauri.config.jsonに細かく権限設定が必要という所でしょうか。上記のファイル操作の例だと、allowList.fs.scope$RESOURCE/*を入れてあげないといけません。
セキュリティ的な観点と、httpやshellでは結局ホワイトリスト設定してあげないといけないので、"all":trueはやめておいた方が良いと思います。

あれよあれよという間にそれっぽいのが作れてしまった

バックエンド側でやらせたかった事が全てAPIの機能で賄えた事もあり、ひな形と機能の検証自体は1日ほどで出来ました。やったぜ。(結局その後API側の変更とか対応がありましたが)

やはり何といってもビルドサイズが小さいのが非常にストレスフリーです。人に触ってもらうときも気軽に共有出来ます。

その他感じたこと(おまけ)

戻り値の型定義で引っ掛かる部分あり

fsのexists()の戻り値がPromose<void>だったり、httpでResponseType.Binaryにした時のResponseの型が普通のarrayだったりして、コードを書く時に引っ掛かりました。直観的じゃないな~とは思いますが、意図してそうなっているのはちょっとわかりません

バックエンドのホットリロードにそこそこ時間が掛かる

フロントエンド側はviteを使っているので、高速にホットリロードが行われるのですが、バックエンド側を弄ったとき(今回だと、tauri.config.jsonしか触ってませんが)は、一度プロセスを落としてバックエンドを再ビルドします。これが5~10秒ほど掛かり、ウィンドウも消えてしまうので、バックエンド側をまめに更新したい時は結構ストレスかもしれません。
調べてみるとRustはまあまあビルドに時間が掛かるようですね。

GitHub Actionsは今の所使わなくてもよい

TauriはGitHub Actions用の設定ファイルが公開されていて、これを使えば簡単にクロスプラットフォーム向けのビルドとリリースが行えるのですが、

  • Windows版以外の需要が無さそう(VOICELOIDやAI VOICEがWindowsのみ)
  • Actionsで出てくる物がインストーラ(.msi)しかない
    • あまり小規模アプリで人のPCのレジストリを汚したくないです。
  • 個人で開発する小規模アプリ
  • ローカルでビルドした方が早い(Actions:10分、ローカル:1分弱)

以上の事から、今のところは個人でビルドした物を配布する事にしました。

Discussion