Swift言語は、アプリケーションやコマンドラインツールでの活用がよく知られており、サーバサイドでの活用もできます。実は、WebAssemblyを使うとWebフロンドエンドでの活用も可能になります。
WebAssembly
WebAssembly は、Webブラウザ上で実行できる実行バイナリ形式です。
この実行バイナリは、Webブラウザに組み込まれた仮想マシン上で実行されます。WebAssemblyはモダンな主要Webブラウザ各種でサポートされています。WebAssemblyの活用事例として、Google Meet、Google Earth、Figma、eBay、などが知られています。
Webブラウザ上で動作するプログラムにはすでにJavaScriptがあります。しかしWebAssemblyは、JavaScriptのような特定のプログラミング言語ではなく汎用的な実行バイナリ形式であるため、さまざまな言語で実行バイナリが作成できます。
WebAssemblyバイナリの生成方法でよく知られているものは以下があります。
- WebAssemblyテキストを記述して生成する
- C/C++ソースコードからEmscriptenで生成する
- Rustソースコードからwasm-packで生成する
- AssemblyScriptソースコードから生成する
SwiftWasm
SwiftでもWebAssemblyバイナリを生成できます。そのためには、SwiftWasm を使います。
SwiftWasmは、Swiftコンパイラに改変を加えてWebAssemblyバイナリが生成できるようにしています。将来的に、本家のSwiftコンパイラに取り込まれることが目標となっています。
SwiftWasmが提供するSwiftツールチェインをインストールすると、WebAssemblyバイナリが生成できます。公式ページをたどってツールチェインのインストールパッケージを入手しても良いのですが、実は次に述べるcartonを使ってインストールするのが簡単です。
carton
carton は、SwiftWasmによる開発をサポートするコマンドラインツールです。
Macの場合、cartonはHomebrewでインストールできます。
いくつかの機能を持つツールですが、たとえば以下の機能があります(バージョン0.17.0現在)。
-
carton sdk
: SwiftWasmのツールチェインをインストールします。 -
carton init
: Swiftパッケージを新規作成します。 -
carton dev
: SwiftパッケージをビルドしてWebAssemblyバイナリを生成します。そして、HTTPサーバを起動します。 -
carton bundle
: SwiftパッケージをビルドしてWebAssemblyバイナリを生成します。そして、デプロイに必要なリソースをまとめます。
ビルドコマンドが2種類ありますが、carton dev
が開発用途のビルド、carton bundle
がリリース用途のビルドです。
簡単なWebAssemblyバイナリの作成と実行
試しに、Swiftパッケージを使わずに簡単なWebAssemblyバイナリを作成してみます。
そのためにまず、cartonでSwiftWasmのツールチェインをインストールします。
carton sdk install
このときのインストール先は $HOME/Library/Developer/Toolchains
以下となります。
インストールしたツールチェインを使ってWebAssemblyバイナリを生成します。
echo 'print("Hello, world!")' > hello.swift
~/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swiftc -target wasm32-unknown-wasi hello.swift -o hello.wasm
WebAssemblyバイナリを実行します。通常はWebブラウザの仮想マシン上で実行する必要がありますが、ここでは簡単な実行手段として wasmer を使います。cartonインストール時にwasmerも一緒にインストールされています。
ターミナルで以下を実行すると、Hello, world!
が標準出力に表示されます。
wasmer hello.wasm
cartonによるWebAssemblyバイナリの作成
WebAssemblyバイナリを作成するためのSwiftパッケージを、cartonを使って作成してみます。
mkdir hello-carton
cd hello-carton
carton init
次のようなファイルが生成されます。通常のSwiftパッケージと同様です。
.
├── Package.swift
├── README.md
├── Sources
│ └── hello-carton
│ └── hello_carton.swift
└── Tests
└── hello-cartonTests
└── hello_cartonTests.swift
hello_carton.swift
の内容は次のようになっています。
@main
public struct hello_carton {
public private(set) var text = "Hello, World!"
public static func main() {
print(hello_carton().text)
}
}
ビルドしてみます。なお、まだSwiftWasmのツールチェインをインストールしていなければ、carton dev
がツールチェインのインストールも実行してくれます。このため、前述の carton sdk install
は実行していなくても大丈夫です。
carton dev
carton dev
は、SwiftパッケージをビルドしてWebAssemblyバイナリを生成します。そして、HTTPサーバを起動し、そのサーバにアクセスするWebブラウザを起動します。
Webブラウザの開発コンソールを見ると、Hello, world!
が出力されていることがわかります。
また、cartonはSwiftソースコードの変更を監視しており、ソースコードに変更があるとすぐにリビルドされてHTTPサーバに反映されます。
JavaScriptの呼び出し
WebAssemblyからJavaScriptの機能を呼び出すことができます。
SwiftWasmの場合、SwiftコードでJavaScriptKitを使います。前述のSwiftパッケージでは、すでにJavaScriptKitがdependenciesに追加されており、すぐに使えるようになっています。hello_carton.swift
を書き換えてみます。
import JavaScriptKit // <- 追加
@main
public struct hello_carton {
public private(set) var text = "Hello, World!"
public static func main() {
let alert = JSObject.global.alert! // <- 追加
_ = alert(hello_carton().text) // <- 変更
}
}
import JavaScriptKit
を追加して、main
関数でテキストを print
する代わりにテキストを alert
で表示するようにしました。
carton dev
を実行したままになっていれば、前述のように、ソースコードを変更するとすぐにリビルドされてHTTPサーバに反映されます。
無事に動作すれば、Webブラウザ上でアラートダイアログに Hello, world!
が表示されます。
TokamakによるUIの作成
SwiftWasmでは、Tokamak というUIフレームワークが利用できます。これにより、WebのUIもSwiftで書けます。
Tokamakを使ったWebフロントエンドアプリのSwiftパッケージが、cartonを使って作成できます。
mkdir TokamakApp
cd TokamakApp
carton init --template tokamak
生成された App.swift
の内容は次のようになっています。
import TokamakDOM
@main
struct TokamakApp: App {
var body: some Scene {
WindowGroup("Tokamak App") {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
Text("Hello, world!")
}
}
TokamakはSwiftUIと同様の記法で書けます。
carton dev
を実行すると、Webブラウザ上に Hello, world!
が表示されます。
さらなる情報
SwiftWasmについて簡単に紹介しました。より詳しい情報は、以下を参照してください。
- SwiftWasmの Documentation
- swiftwasm/awesome-swiftwasm