2024年2月2日にTauri 2.0がβ版となりました。昨年から個人的にいくつかTauriの1系でデスクトップアプリケーションを開発してきたのですが、ここが辛かった!というのを列挙してみました。
因みに公開しているのは以下となります。
尚、Iron Beads Editor(以下IBE)に関しては元々Vanilla.jsでweb側を作っていて、それの機能追加版となります。
なぜTauriを選択したのか?
まずTauriを選択する前に以下のプラットフォームを検討しました。
Platform | 所感とか |
---|---|
Electron | The 王道!Chromiumを同時にインストールさせる、ノウハウ沢山しかし、バイナリがでかい |
gluon | 各配布先のユーザーのnode.jsを使うので非エンジニアに対してハードル高杉FireFox対応してるDenoやBunが使える (だから何?) |
Tauri | Rust製…今回の記事 |
neutralino | インドの人が開発。DBが貧弱と言われるがjsonで管理できるものなら問題ない感じ |
ElectronはLinux用のGUIツールが必要だった際にやったことあったので、neutralinoとTauriで同時に開発していったのですがドキュメントの見やすさでTauriに軍配が上がりました。
それでも色々ひっかかりました。以下は本題のひっかかり所です。
JS側のサンプルは充実しているのにRust側のExampleが貧弱
多分、Tauri側のコンセプトがRustを最低限書けばあとはJSを書くだけで動くというのがあるのでしょうが明らかにRust側のサンプルが少なすぎるんですね。
例えば、windowのタイトルを動的に変更したい場合JS側はsetTitleにきちんとサンプルがありますが、Rust側のset_titleには最低限の記述しかありません。
ググると必ずJS側のサンプルばかりがhitして「Rust側でどうやって実装するんだっけ?」みたいな時に何度か迷子になっていました。(そもそもmethodが存在するか?のチェックを何度もしていたので迷子になった)
開発効率を考えるとRust側の方のdocsにもExampleがあった方が親切だと思いました。
WRYに引きづられる
当たり前のことですが結構重要だったので記述します。
TauriはWebViewの部分をWRY(WebView Rendering Library)を使っています。(Servoの様な代替のものも検討されていますが、多くはWRYを使っていると思っています)
「何が言いたいか?」というとChromeとか最新ブラウザで動くものをTauriに移植しようとしてもWRYで対応していないタグやCSSがあって動かないということです。
実際にIBEのweb版ではdialogタグを使っていたのですが、WRYでは対応してませんでした。
<dialog>ダイアログの内容</dialog>
他にもdomの画像化に対してhtml2canvasを使っていたのですが、cssのcounter-increment部分が上手くできなくてhtmlToImageで無理やり実装しました。
release版だけ起こる謎のバグ
前述したWRYの対応していないタグに似ていますが、JSでHTMLのinput type="color"の値を動的に変更しようとするとdev版では何も問題ないのにBuildしてrelease版を使うとWRY部分だけ再起動してしまう謎のバグがありました。(ログにも出ない)
[2024/02/15追記]
思い出したことがあったので追記します。
日本語と英語対応しようと思っていた時に戻り値違いがあってdevだと「ja-JP」でbuildすると「en-JP」になることもありました。
#[tauri::command]
fn is_japanese() -> bool {
let current_locale = current_locale::current_locale();
let current_lang = current_locale.ok().unwrap();
//println!("current_lang: {}", current_lang);
//devだと「ja-JP」buildだと「en-JP」が戻り値になる
if current_lang.ends_with("JP") {
return true;
}
return false;
}
[追記ここまで]
Mac/Windowでクレートの挙動が違う…
String Scouterでは自分の拘りもあって変わったUIにしました。
で、やっぱり透過をしたら影をつけたくなるのでwindow-shadowsをやったところWindowsで以下のようになりました。(四角のWindowにしか対応してない…)
また、所謂send keyとしてenigoを使いましたが、Macでは「Key::Layout('c')」で落ちました。
で、仕方なくrawを使うことで対応できたんですが、今度はWindowsだと動かなくて…
if cfg!(target_os = "macos") {
enigo.key_down(Key::Meta);
enigo.key_click(Key::Raw(8));
enigo.key_up(Key::Meta);
} else {
enigo.key_down(Key::Control);
enigo.key_click(Key::Layout('c'));
enigo.key_up(Key::Control);
}
みたいな処理で対応しました。
OSで挙動が違う
まぁ、クレートなら仕方ないと思いますがこっちはTauriそのものです。
String Scouterでは必要な時にアプリケーションのWindowをActive状態(focusをする)にしていたのですが、Macだとhideして状態のwindowをshowしていなくてもset_focusすればActiveになるんですが、Windowsだと絶対にhideしたものはshowしなければダメでした。
let window = app.get_window("main").unwrap();
window.hide().unwrap();
//↑の状態で↓のmethodを叩くとMacはActiveになるがWindowsはダメ
window.set_focus().unwrap();
//ちゃんとhideしたらshowしましょう
window.show().unwrap();
menuに対するselectedをチェックするメソッドがない(文字列をチェックするのもない)
以下のようなメニューがあった際、通常ならば「チェックの有無」でToggleすると思うのですが、「set_selected(true)」はあるのに「get」がなくて、これを不整合なくやるには一々flagで管理するか何らかのstorageなどに保存していくことになるので面倒でした。
(個人的には色々検討した結果Toggleにはしなかったのですが、クレートを使わずに対応する場合だとlocalstorageに入れるなどでしょうか?)
AIが使えない(GeminiもChat GPTも架空のmethodを教えてくる)
Chat GPTに関しては情報が古めなこともあり仕方ない部分もありますが、Gemini(旧Bard)も存在しないmethodをガンガンおすすめしてきて(前述したset_selectedのget版とか)当たり前ですが、こういうあまり需要がなかったりニッチなものはAIも役に立たないなぁと思いました。
存在しないクレートをおすすめしたりするのは本当勘弁して欲しかったです。
尚、精度としてはGeminiの方がリファクタリングも含めて圧倒的でした。
それでもTauriは楽だ!
もっとひっかかり所はあったのですが、印象的なものを記述しました。
まぁ、String ScouterのようなものならばAutoHotkeyなどでサクッと作れますが、GUIにこだわったりOSを超えてとなると微妙です。(特に昨今同じOSでもCPUがIntelとArm系が混じっていたりしますし)
Tauriはマルチプラットフォームなのに出てくる記事がMacのみだったりWindowsのみだったり複数のOSでbuildした記事があまりなく四苦八苦しました。
Tauriは複数OSのバイナリも「Github Actionsがあれば楽勝!」みたいなのも見かけたのですが、ちゃんと実機である程度buildできる状態にしてからでないとCIに任せられないのはElectronでもGoでもなんでも一緒なのと、もうちょっとマルチプラットフォームでのBuildの記事やノウハウが広がるといいなと、version2.0に期待しています。
とは言え、Electronと比較してバイナリサイズの小ささやRustの恩恵を得られますし、QtやGTKでは表現し辛いGUIもGLなんかを書かずにCSSでサクっと作れるのは凄く恩恵があると思います。
個人的にはServoに期待して今後も使っていこうと思いました。