2025/03/31

mclocks を Electron から Tauri に切り替えた

mclocks

https://github.com/bayashi/mclocks

mclocks はデスクトップに複数の日時を表示するアプリケーションです。Windows と Mac 向けのバイナリをビルドして配布しています。5年前に Electron を使って書きました。近年は細々セキュリティアップデートだけしていたのですが、先日 Program size issue という issue をもらいました。配布しているバイナリがでかすぎる、ということです。

https://github.com/bayashi/mclocks/issues/122

まあ、mclocks は複数のタイムゾーンの日時をただ表示するだけのシンプルなアプリケーションなので、それが 117MB もあるというのは驚きに値します。初代ドラクエは 64KB らしいので、あからさまにでかい。

Electron から Tauri へ

とはいえいまどきディスクもメモリもGB単位の時代なので、そんな気にしなくていいのでは、と思っていたのですが、最近話題の Tauri というフレームワークなら軽量化できるらしいと聞いたのでぼちぼち移行してみました。

先にサイズがどんな感じになったかだけ書いておくと、

ビルドしたバイナリが、.exe で 157MB が 1.78MB と 1/100 になりました。小っさ!!

.dmg は 101MB が 4.83MB になりました(1/20)。

とはいえこれは配布バイナリのサイズなので、ダウンロードして転送するまでの話です。

インストールしたアプリケーションバイナリのサイズはどうかというと、538MB が 8.23MB になりました(windows)。まあまあインパクトあるかも。

そして気になる実行時のリソース消費ですが、CPU負荷が 0.3% から 0% に(0.0X%なのかな)、メモリ使用量は 89.0MB から 86.1MB になりました。メモリ使用量はさすがにそれほどのインパクトはなかったのですが、全体的にはそれなりに軽量化されたようでした。

Tauri マイグレーション

さて、そいういうわけで Electron から tauri へのマイグレーションの中身についてですが、Tauri は公式ドキュメントが充実しているので、あまり細かいところはさておき、気になった点をいくつか書き残そうと思います。

Tauri 2

今回は Tauri v2 に移行しました。世にあふれているブログは v1 向けが多いので、公式の v2 ドキュメントを頼りにしましょう。とはいえ、v1 そのままの点も多いので v1のドキュメントもけっこういけたりはします。あと、ChatGPTなんかも v2 での書き方を明示的に聞いても余裕で v1 のコードを出してきたりするので油断できません。

pnpm + Vite

Electron のときは CommonJS で書いていましたが、今回はできるだけナウいツール群をためしたいということで、ESM, pnpm + Vite で開発しました。まあ、単体アプリ開発するだけなら npm でもいいし、じつは最初は webpack ではじめて途中で Vite に乗り換えたりしたというのは内緒です。また、何度も書いているように mclocks アプリ自体はシンプルなものなので、JSフレームワークは使わず VanillaJS です。

$ pnpm create tauri-app --tauri-version 2
✔ Project name · mclocks
✔ Identifier · com.bayashi.mclocks
✔ Choose which language to use for your frontend · TypeScript / JavaScript - (pnpm, yarn, npm, deno, bun)
✔ Choose your package manager · pnpm
✔ Choose your UI template · Vanilla
✔ Choose your UI flavor · JavaScript

地味に create tauri-app した初期状態だと、Windowsではコードの改行コードが CRLF になっててめんどかったです。変換するワンライナーは ChatGPT に尋ねました。

ローカル開発

create tauri-app して pnpm install するとすぐ初期アプリが起動できます。

pnpm tauri dev

最初に、rust 側に devtools が自動で起動するコード仕込めば快適です。公式ドキュメントの Debug のページ にいろいろ TIPS があります。

Vite 導入

pnpm add -D vite して、vite.config.js を追加しておしまい。公式にあるやつをコピペしました。一点だけ、Viteで起動するサーバの port は tauri.conf.json の devURL のポート番号と一致してないとだめです(そらそう)。

あと、ファイルのレイアウトは create tauri-app したときと微妙に変えています。主に index.html をプロジェクトトップに持ってきている。

謎の warning

Vite を導入すると pnpm install したときに謎の warning が表示されるようになりました。

Ignored build scripts: esbuild.
Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.

esbuild は Vite が使っているバンドルツールらしく、バンドルするとき以外は不要だから無視するようにしろという警告ですね。

package.json に以下の記述をすると消えます。

"pnpm": {
  "onlyBuiltDependencies": ["esbuild"]
}

LogicalSize と PhysicalSize

mclocks で表示される時計は config によって横幅が可変になります。横幅はフォントやフォントサイズや時計のフォーマットによって変化するので、算出するのが簡単ではありません。そこで、mclocks では時計全体を実際にレンダリングしてみて、必要なサイズを取得してアプリケーション全体のウィンドウサイズを動的に決定するということをしています。

その際に、Element に LogicalSize と PhysicalSize というのがあるのですが、よくわからないけど PhysicalSize だと見えているサイズがそのまま取得できず、LogicalSize を用いることでうまくいけました。フロントエンドは本当に難しいですね。

ChatGPTによると違いは以下のようだそうです。

1. LogicalSize

    論理的サイズは、ディスプレイのピクセル密度(DPIやスケーリング)を考慮せず、アプリケーション内での「論理的な」サイズを意味します。
    通常、1px は1論理ピクセルに対応しますが、スクリーンの解像度やスケーリング設定によっては、物理的なピクセル数が変わります。
    例えば、DPIスケーリングが2倍(200%)の設定であれば、LogicalSize は変わらず、物理的には実際のピクセル数は倍になります。
    LogicalSize は通常、アプリケーションのレイアウトやデザインに使われるサイズで、スケーリングに依存しません。

2. PhysicalSize

    物理的サイズは、実際のスクリーン上のピクセル数を指します。
    物理サイズは、ディスプレイのピクセル密度(DPI)やスケーリングに依存します。たとえば、DPIスケーリングが有効になっていると、実際の物理的ピクセル数は論理的なピクセル数の倍になります。
    これは、実際に表示されるウィンドウのピクセル数で、スクリーンやOSのスケーリング設定に影響されます。

まとめ

    LogicalSize は論理的なサイズ(スケーリングを考慮したサイズ)で、UIのデザインやレイアウトに使用されます。
    PhysicalSize は物理的なピクセル数を指し、実際に画面に表示されるサイズです。

なるほど、今回の用途だと PhysicalSize っぽいわ(文字通りなので予想つくけど)。

アイコン画像生成

tauri が1枚の画像からアイコン画像を変換生成してくれるコマンド持ってます。便利。

ビルド

ひとしきり開発したら手元でビルドを試します。

pnpm tauri build

よさそうなら github actions で複数の OS 向けのビルドも仕込みます。

公式の action が用意されているのでそれを使います。コピペですんなりビルドされました。素晴らしい。

まとめ感想

Tauriは確かに軽量でした。開発体験も非常によく、アプリケーションロジックを書くことに集中できるところが良いと思いました。Electron のときは Electron の事情みたいなのを知ったうえでコードでもアプリケーションロジック以外のことをけっこう書く必要があった印象。とはいえ、今回の Tauriマイグレーションでは Electron の経験があるからすんなり実装できた面もおおいにあるとは思いますが。

あと、いまの mclocks の実装ではローカルの config設定ファイルを rust側で読んでいるのだけど、tauri-plugin を使うとJS側でも読めるらしく、mclocks全体を rust なしでも構成できそうというのにあらかた完成したあたりで気づいたけど、それはもう気づかなかったことにしている。チラ見した感じ、tauri-plugin はけっこう充実していて、rust 側でやりそうなことも JS 単独でできることがあったりするようなので、これは先にチェックしておいた方が良い。

あと、window-state というプラグインを導入しようと試みたけど、謎のエラーが出てあきらめました。アプリの起動位置やサイズを保存復元してくれる便利なものなのだけど、まあこれ系は案外うまく動かないことも多いので(マルチディスプレイだったりすると)、また気が向いたら試します。(移行前のElectron版 mclocks にも入っているけどあまりうまく動いている印象がない)

総じて今回の開発では、公式ドキュメント以外はWeb検索せずに ChatGPTに尋ねて頑張りました。この手の作業にはうってつけのバディですね。

おわり。

サイト内検索