WebUIについて調べた

WebUIはデスクトップアプリを作るためのライブラリ。HTML, CSS, JavaScriptでフロントエンドを作り、バックエンドをC, C++, Python, Go, TypeScriptなどの言語で開発できる。システムにインストールされているWebブラウザで動作する

https://webui.me/webui.me

2023年にhassandragaさんが公開し、V言語コミッタのttytmさんらも参加した

本体はCで開発されていて、Python, Go, TypeScriptにバイディングが提供されている

似た技術としてはElectronやTauri、Gluonなどが存在する

laiso.hatenablog.com

zenn.dev

アーキテクチャについて

ElectronやTauriと比較すると、WebUIのアーキテクチャはWebアプリをブラウザで開くだけなのでより単純かつ制約が大きい

開発者にとってはブラウザを使ってプログラムにGUIを付けられるライブラリであり

ユーザーにはChromeのdesktop shortcutsのようにスタンドアロンなウィンドウで起動するWebアプリになる

他のフレームワークとの簡単な比較図を作った

Presentation Main Program Bridge
Electron Chromium Node.js IPC
Tauri WebView Rust IPC(JSON-RPC)
WebUI Web Browser C and bindings HTTP(WebSocket)

WebUIでデスクトップアプリを起動する時のフローが以下になっている

  1. Pythonなどで記述したMainプログラム(hello_world.py)を実行
  2. WebUIがシステムにインストールされているウェブブラウザを呼び出す
  3. 専用のプロファイルでMainプログラムが実行するhttp://localhost:53949を開いてデスクトップアプリっぽく見せる
git clone https://github.com/webui-dev/python-webui
cd python-webui/examples
pip install webui2
python hello_world.py
MyWindow = webui.window()
MyWindow.show(login_html) # 描画するHTMLのテキスト

このデスクトップアプリのシステムWindowは「Google Chrome」になっていて以下のプロセスで実行されている

ps x | grep .WebUI

/Applications/Google Chrome.app/Contents/MacOS/Google Chrome --user-data-dir=/Users/laiso/.WebUI/WebUIChromeProfile --no-first-run --no-proxy-server --safe-mode --disable-extensions --disable-background-mode --disable-plugins --disable-plugins-discovery --disable-translate --disable-features=Translate --bwsi --disable-sync --disable-sync-preferences --disable-component-update --allow-insecure-localhost --app=http://localhost:53949

Mainプログラムとブラウザのブリッジ連携

Mainプログラム側からブラウザの値を参照するにはJavaScriptコードを送る

res = e.window.script("return document.getElementById(\"MyInput\").value;")
if res.data == "123456":
    print("Password is correct.") 

逆にブラウザ側からMainプログラムの関数を呼び出す時はwindows.webuiオブジェクト経由でバインドしておく

def check_the_password(e : webui.event):
    #...

MyWindow.bind('CheckPassword', check_the_password)
<button onclick="webui.CheckPassword()">Check Password</button>

もしくはHTMLのid要素に暗黙的にバインドされている

<button id="CheckPassword">Check Password</button>

これを使うためにHTML側には <script src="webui.js"></script> のおまじないが入ってないといけない

この中身がwebui /bridge/で、TypeScriptで書いたWebSocketクライアントをさらにCのヘッダにhexにして埋め込んでいる

埋め込んだ文字列をローカルサーバーの /webui.js として返している

なんでそんなことを…… と最初思ったが、バイナリに埋め込み静的ライブラリとして配布するため?

その他の特性

  • あくまでライブラリでデスクトップアプリを配布用にパッケージングする仕組みなどはない
    • 例えばMainプログラムの実行にPythonが必要なら利用する環境にもインタプリタがないといけない
  • ブラウザの中で動いているローカルなWebアプリなので、その外側のOSの機能(システムメニューなど)まではアクセスできない

ドキュメントは https://webui.me/docs/

Disclaimer

この記事はWebUIのコア実装の理解に焦点を置いています。ElectronやTauriと比較し、WebUIの利用を薦めるものではありません

筆者はデスクトップアプリの開発にはプラットフォームの標準SDKを使います