
はじめに
Wailsは、Goを使用したクロスプラットフォームのデスクトップアプリケーション開発を容易にするプロジェクトです。フロントエンドには組み込みブラウザではなくネイティブのWebViewコンポーネントを使用することで、軽量さを保ちながら、世界で最も普及しているUIシステムの力をGoにもたらします。
バージョン2は2022年9月22日にリリースされ、次のような多くの機能強化が導入されました。
- 人気のViteプロジェクトを活用したライブ開発
- ウィンドウ管理とメニュー作成のための豊富な機能
- MicrosoftのWebView2コンポーネント
- Goの構造体に対応するTypeScriptモデルの生成
- NSISインストーラーの作成
- 難読化ビルド
現在、Wails v2は、機能豊富なクロスプラットフォームのデスクトップアプリケーションを作成するための強力なツールを提供しています。
この記事では、プロジェクトの現状を確認し、今後改善できる点を検討します。
現在の状況
v2のリリース以降、Wailsの人気が高まっていく様子には目を見張るものがあります。コミュニティの創造性と、Wailsを使って作られている素晴らしい成果物には、いつも驚かされています。人気が高まるにつれて、プロジェクトに注目する人も増えました。それに伴い、機能リクエストやバグ報告も増えています。
時間の経過とともに、このプロジェクトが直面している特に差し迫った問題をいくつか特定できました。また、プロジェクトの進展を妨げている要因もいくつか明らかになりました。
現在の問題
プロジェクトの進展を妨げていると考える領域は、次のとおりです。
- API
- バインディング生成
- ビルドシステム
API
現在、Wailsアプリケーションを構築するためのAPIは、2つの部分で構成されています。
- Application API
- Runtime API
よく知られているように、Application APIには1つの関数しかありません。それが、アプリケーションの動作を制御する多数のオプションを受け取るRun()です。これは非常に簡単に使用できる一方で、制約も非常に大きいものです。基盤となる複雑さの多くを隠す「宣言的」なアプローチです。たとえば、メインウィンドウへのハンドルがないため、直接操作できません。そのためにはRuntime APIを使用する必要があります。複数のウィンドウを作成するなど、より複雑な処理を行おうとすると、これが問題になります。
Runtime APIは、開発者向けに多くのユーティリティ関数を提供しています。次のものが含まれます。
- ウィンドウ管理
- ダイアログ
- メニュー
- イベント
- ログ
Runtime APIには、満足していない点がいくつかあります。まず、「context」を受け渡す必要があります。これは煩わしいだけでなく、contextを渡したにもかかわらずランタイムエラーが発生する初心者の開発者を混乱させます。
Runtime APIの最大の問題は、単一のウィンドウだけを使用するアプリケーション向けに設計されていることです。時間の経過とともに複数ウィンドウへの需要が高まりましたが、このAPIはそれにあまり適していません。
v3 APIについての考察
次のようなことができたら素晴らしいと思いませんか?
func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}このプログラムによるアプローチは、はるかに直感的であり、開発者がアプリケーションの各要素を直接操作できます。現在ウィンドウ向けに用意されているすべてのランタイムメソッドは、そのままウィンドウオブジェクトのメソッドになります。その他のランタイムメソッドは、次のようにアプリケーションオブジェクトへ移動できます。
app := wails.NewApplication(options.App{})
app.NewInfoDialog(options.InfoDialog{})
app.Log.Info("Hello World")これは、より複雑なアプリケーションを構築できる、はるかに強力なAPIです。また、GitHubで最も多くの賛成票を集めている機能である複数ウィンドウの作成も可能になります。
func main() {
app := wails.NewApplication(options.App{})
myWindow := app.NewWindow(options.Window{})
myWindow.SetTitle("My Window")
myWindow.On(events.Window.Close, func() {
app.Quit()
})
myWindow2 := app.NewWindow(options.Window{})
myWindow2.SetTitle("My Window 2")
myWindow2.On(events.Window.Close, func() {
app.Quit()
})
app.Run()
}バインディング生成
Wailsの主要機能の一つは、GoのメソッドをJavascriptから呼び出せるようにするバインディングの生成です。現在の生成方法は、いささか場当たり的です。特殊なフラグを付けてアプリケーションをビルドし、生成されたバイナリを実行して、リフレクションによって何がバインドされているかを判定します。このため、鶏と卵のような状況が生じます。バインディングなしではアプリケーションをビルドできず、アプリケーションをビルドしなければバインディングを生成できません。これを回避する方法はいくつもありますが、最善なのは、そもそもこのアプローチを使わないことです。
Wailsプロジェクト用の静的解析ツールを作成する試みは何度かありましたが、あまり進展しませんでした。近年では、このテーマに関する資料が増えたため、以前より多少取り組みやすくなっています。
ASTを使用するアプローチは、リフレクションに比べてはるかに高速ですが、大幅に複雑です。まずは、コード内でバインディングを指定する方法に一定の制約を設ける必要があるかもしれません。目標は、最も一般的なユースケースをサポートし、その後で対応範囲を拡大することです。
ビルドシステム
APIの宣言的なアプローチと同様に、ビルドシステムもデスクトップアプリケーションのビルドに伴う複雑さを隠すために作られました。wails buildを実行すると、背後で多くの処理が行われます。
-
バインディング用のバックエンドバイナリをビルドし、バインディングを生成する
-
フロントエンドの依存関係をインストールする
-
フロントエンドのアセットをビルドする
-
アプリケーションアイコンが存在するかを判定し、存在する場合は埋め込む
-
最終的なバイナリをビルドする
-
darwin/universal向けのビルドの場合、2個のバイナリ(darwin/amd64用とdarwin/arm64用)をビルドし、lipoを使用してFat Binaryを作成する -
圧縮が必要な場合は、UPXを使用してバイナリを圧縮する
-
このバイナリをパッケージ化するかどうかを判定し、パッケージ化する場合は次の処理を行う。
- アイコンとアプリケーションマニフェストがバイナリにコンパイルされていることを確認する(Windows)
- アプリケーションバンドルを構築し、アイコンバンドルを生成して、アイコンバンドル、バイナリ、Info.plistをアプリケーションバンドルにコピーする(Mac)
-
NSISインストーラーが必要な場合は、それをビルドする
このプロセス全体は非常に強力である一方、内部の仕組みがほとんど見えません。カスタマイズもデバッグも非常に困難です。
v3 ではこの問題に対処するため、Wails の外部にあるビルドシステムへ移行したいと考えています。しばらく Task を使ってきましたが、私はとても気に入っています。ビルドシステムの構成に優れたツールであり、Makefile を使ったことがある方なら比較的なじみやすいでしょう。
ビルドシステムは Taskfile.yml ファイルを使って構成し、このファイルはサポート対象のどのテンプレートでもデフォルトで生成されるようにします。アプリケーションのビルドやパッケージ化など、現在のすべてのタスクを実行するために必要な手順をこのファイルに含めることで、容易にカスタマイズできるようになります。
このツールは Wails CLI の一部となるため、外部依存として用意する必要はありません。つまり、引き続き wails build を使用でき、現在と同じ処理がすべて実行されます。ただし、ビルドプロセスをカスタマイズしたい場合は、Taskfile.yml ファイルを編集できます。また、ビルド手順を容易に把握でき、必要であれば独自のビルドシステムも使用できます。
ビルドというパズルで欠けているピースは、アイコン生成、圧縮、パッケージ化など、ビルドプロセスを構成する個々の操作です。多数の外部ツールを必須にすることは、開発者にとって望ましい体験ではありません。この問題に対処するため、Wails CLI はこれらすべての機能を CLI の一部として提供します。これにより、追加の外部ツールがなくてもビルドは従来どおり動作し、その一方で、ビルドのどの手順でも任意のツールに置き換えられます。
これにより、ビルドシステムの透明性が大幅に向上し、カスタマイズが容易になるとともに、これまで指摘されてきた多くの問題に対処できます。
得られる成果
これらの前向きな変更は、プロジェクトに大きなメリットをもたらします。
- 新しい API ははるかに直感的になり、より複雑なアプリケーションを構築できるようになります。
- バインディング生成に静的解析を使用することで、処理が大幅に高速化し、現在のプロセスに伴う複雑さの多くが軽減されます。
- 実績のある外部ビルドシステムを使用することで、ビルドプロセスが完全に可視化され、高度なカスタマイズが可能になります。
プロジェクトのメンテナーにとっては、次のメリットがあります。
- 新しい API は、保守がはるかに容易になり、新機能や新しいプラットフォームにも対応しやすくなります。
- 新しいビルドシステムは、保守と拡張がはるかに容易になります。これが、コミュニティ主導のビルドパイプラインからなる新たなエコシステムにつながることを期待しています。
- プロジェクト内の関心事をより明確に分離できます。これにより、新機能や新しいプラットフォームを追加しやすくなります。
計画
これに向けた実験の多くはすでに完了しており、良好な結果が得られています。現時点ではこの作業のスケジュールは決まっていませんが、2023 の第1四半期末までに Mac 向けアルファ版をリリースし、コミュニティの皆さんにテストや検証を行ってフィードバックを寄せていただけるようにしたいと考えています。
まとめ
- v2 API は宣言的で、多くの仕組みを開発者から隠しており、複数ウィンドウなどの機能には適していません。よりシンプルで直感的、かつ強力な新しい API を作成します。
- ビルドシステムは内部の仕組みが見えにくく、カスタマイズも困難です。そのため、すべてを可視化できる外部ビルドシステムへ移行します。
- バインディング生成は低速で複雑なため、静的解析へ移行し、現在の手法に伴う複雑さの多くを解消します。
v2 の内部には多くの労力が注ぎ込まれており、堅牢に仕上がっています。今こそ、その上位レイヤーに取り組み、開発者にとってはるかに優れた体験を実現するときです。
皆さんにも、私と同じくらい期待していただければ幸いです。皆さんのご意見やフィードバックを楽しみにしています。
それでは、
‐ Lea
追伸:皆さんや皆さんの会社で Wails を有用だと感じていただけましたら、プロジェクトへのスポンサー支援をご検討ください。ありがとうございます!
追伸その2:はい、これは Wails で構築したマルチウィンドウアプリケーションの本物のスクリーンショットです。モックアップではありません。本当に動作しています。素晴らしい出来です。近日公開予定です。