🐰

巷で話題沸騰中のElectrobunでMarkdownエディタを作成した感想

に公開

はじめに

ElectrobunでWindows用のWYSIWYGなMarkdownエディターを作成しました。
基本的なMarkdownの文法はもちろん、mermaidkatexhtmlをLive Previewで編集できるエディターです。
デザインは多くのMarkdownエディターがモダンでミニマルなデザインにしているので、ネオブルータリズムなデザインにしてみました。

https://github.com/Catharacta/editary

そもそもElectrobunって何?

Electrobunは、Bunをベースにした軽量なデスクトップアプリケーション開発フレームワークです。ElectronとBunを合わせたネーミングです。アイコンは白いうさぎなので、Bunny(うさぎ)にも掛けられています。

リポジトリ
https://github.com/blackboardsh/electrobun

公式サイト
https://blackboard.sh/electrobun/docs/

主な特徴とアーキテクチャ

  • メインプロセスにBunを採用
    Node.jsよりも高速なスタートアップとメモリ効率を誇る Bun を採用しています。
  • ネイティブ WebView の利用
    ElectronのようにChromiumを丸ごと同梱するのではなく、OS標準のWebView(WindowsならWebView2、macOSならWebKit)を利用します。
  • TypeScript/JavaScript完結
    TauriのようにUI以外のロジック(メインプロセス)を書くためにRustを学ぶ必要がなく、Webフロントエンドの知識だけでデスクトップアプリが完結します。
  • ビルド・配布ツールの統合
    アプリのパッケージング、コード署名、そしてバイナリ差分による軽量な自動アップデート機能などが標準で提供されています。

なぜElectrobunを選んだのか

既存のデスクトップアプリ開発における定番フレームワークと、Electrobunを比較すると以下になる。

フレームワーク メイン言語 描画エンジン 配布サイズ ビルド速度
Electron Node.js(JS/TS) Chromium(同梱) 100MB〜 普通
Tauri Rust OS標準WebView 数MB〜 非常に遅い
Electrobun Bun(JS/TS) OS標準WebView 数MB〜* 爆速

※ Electrobunの配布サイズは公称値。実際にはBunランタイムが同梱される。

Electrobunを選んだ理由は以下が決め手である。

  • Electronの悩み(サイズ・メモリ)を解決: OS標準のWebViewを利用するため、ElectronのようにChromiumを丸ごと同梱する必要がなく、軽量。
  • Tauriの悩み(Rust・ビルド時間)を回避:
    Rustコンパイルが不要なため、Tauriで20分以上かかることもあるリリースビルドの待ち時間から解放される。
  • Bunによる実行パフォーマンス: メインプロセスがNode.jsではなくBunで動くためファイル I/Oなどの処理速度にも期待できる。

Electrobunを使うべき?

アプリを開発した感想としては、現状ではElectronやTauriを差し置いて、Electrobunを使用する明確なメリットは見当たらなかった。以下がその理由となる。

アプリの実行にBunが必要

Bunをランタイムに使用するので、アプリの配布にはBunを同梱する必要がある。Bun自体のサイズはターゲットOS・CPU・ビルド設定によって変化するが、大体、50MBから100MBを超えることもある。
公式サイトには「14MB」と記載されているが、さすがにそこまでサイズが小さくならない。ビルドした自己解凍パッケージはそこそこ小さくなるが、それでも解凍前でも50MB以上、アプリ自体のサイズは100MB以上になることは十分あり得る。
WebViewを使うことでChromium分は削減できているが、Bun本体が入ることで、結局大容量になる。「Tauriより大きく、Electronよりは小さい」という中途半端な位置に落ち着いてしまい、それならElectronでいいんじゃないか?と思ってしまう。

バグが多い

まだリリースされたばかりなので、仕方がない部分もあるが、デスクトップアプリとして「当然動くべき」機能の多くが未実装、あるいは壊れている。結局、以下の機能はFFI(Windows API)を直接叩いて解決するしかなかった。

1.ファイルの新規保存ができない

  • 症状: Electrobunには、ファイルを開くダイアログを起動するAPIは存在するが、ファイルを保存するダイアログを起動するAPIが存在しないので、ファイルを保存する場所を選択できない。
  • 解決策: nativefiledialog-for-bunというライブラリを自作して、FFI経由でC言語のネイティブダイアログを直接呼び出している。

https://github.com/Catharacta/nativefiledialog-for-bun

2. インストール関連のあれこれ

  • 症状: 標準のパッケージング機能が不十分。

    • 標準機能でインストールしても、インストールされたアプリ一覧には表示されない。
    • アプリのアイコン設定において、Electrobunの開発者の開発環境のディレクトリパスがハードコーディングされているため、electrobun.config.tsでアプリアイコンのパスを設定してもビルドされた.exeに反映されない。
    • 標準機能でインストールされたアプリフォルダの内部に自己解凍前のファイルが残っている。
    • 標準機能でインストールしたアプリのフォルダ内のアンインストール用と思われるレジストリファイルを使用してもアンインストールできない。
  • 解決策: electrobun-builder-for-windowsを自作。NSISとWIXでのパッケージングに対応して、上記のバグを解決。しかし、タスクバーのアイコンを右クリックして表示されるメニューのアイコンと名前がBunのままなのは修正できなかった。(原因がわからない。。。)

https://github.com/Catharacta/electrobun-builder

3. 高精細(High-DPI)ディスプレイで UI がぼやける

  • 症状: ElectrobunがOSに「高解像度対応」を通知しないため、4Kモニターなどで表示がぼやける。
  • 解決策: user32.dllSetProcessDpiAwarenessContextを BunのFFI経由で直接呼び出す処理を自作。これをアプリのメインループが走る前に実行するように仕込むことで、なんとか回避している。

定義箇所は以下になる。
引数に-4(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)を渡すことで、モニターごとの高解像度設定を有効にしている。

src/bun/platform-dpi.ts
/**
 * Initialize DPI awareness for the process to prevent blurry UI on Windows.
 */
export function initializeDpiAwareness(): void {
    if (process.platform !== "win32") return;
    try {
        // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 is -4
        // Passing -4 as isize instead of pointer avoids Bun FFI errors
        if (user32.symbols.SetProcessDpiAwarenessContext) {
            user32.symbols.SetProcessDpiAwarenessContext(-4);
        } else {
            user32.symbols.SetProcessDPIAware();
        }
    } catch (e) {
        console.error(`[FFI] DPI initialization failed:`, e);
    }
}

実行箇所は以下になる。メインウィンドウ(BrowserWindow)が生成されるよりも前に実行されている。ウィンドウが作成された後ではこの設定は効かないため、ここで明示的に呼び出している。

src/bun/main.ts
initializeDpiAwareness();

4. ウィンドウのサイズが変更できない(未解決)

  • 症状: 最小化・最大化はAPI経由で可能だが、マウスでウィンドウの端を掴んでリサイズすることができない。
  • 原因: OS標準フレーム(タイトルバーがある状態)ならOSがウィンドウの境界線(1px程度の領域)を自動的に「リサイズ用ハンドル」として認識し、マウスドラッグを処理してくれる。
    しかし、カスタムタイトルバー(titleBarStyle: "hidden")を使用すると、フレームの制御権がElectrobun側に移るが、そこでのマウスイベントやフレーム情報のハンドリングが不十分なため、自由なドラッグリサイズが実現できない。これに関しては、原因はわかっているがライブラリなどの付け焼刃の対策では解決できなかった。

まとめ

バグの修正や不足している機能が実装されない限り、ElectronやTauriに代わってこれを採用するのは厳しそう。
CarrotsというプラグインのシステムやElectrobunny.aiという謎のプロジェクトも進行しているようなので、これからに期待したい。

https://electrobunny.ai/

Discussion