Swiftで動的Webサイト
はじめに
今回は、SwiftでServersideのソリューションを開発して形になってきたので、この場を借りて発表したいと思います。実は2025年の夏頃からGitHubやAWSでデモサイトを公開しているのですが、記事などは何も書いていなかったので、Swiftでサーバーサイド開発の可能性に興味がある方がいれば、ぜひ続きを読んでいただけると嬉しいです。
プロジェクトリンク:
きっかけ - Igniteとの出会い
このプロジェクトのきっかけは、Paul Hudson氏の「Ignite」というプロジェクトです。2025年のTry! Swift カンファレンスでも発表されていました。YouTubeでも解説動画が公開されています。
IgniteのアイデアとDSL
アイデアはSwiftのDSL機能を使って、HTMLのような感覚でSwiftのコードが書けるというものでした。Igniteから引用するとこんな感じでWebサイトが書けます。
Text("Swift rocks")
.font(.title1)
Text(markdown: "Add *inline* Markdown")
.foregroundStyle(.secondary)
Link("Swift", target: "https://www.swift.org")
.linkStyle(.button)
Divider()
Image("logo.jpg")
.accessibilityLabel("The Swift logo.")
.padding()
HTMLと違ってコンパイルするので、実行時に文法や構造の崩れに気がつくのではなく、ビルド時にエラーになります。余計な心配が一つ減るわけです。というか、なによりワクワクしますよね。
静的サイトの限界
自分もHello Worldサイトで試してみようと思いましたが、ここで一つ気になることに気がつきました。なんと、「Ignite」は静的なサイト構築用だということです。あれ、動的なサイトはできないの?う〜ん、なんか凄く残念です。
アイデア - 動的なSwiftウェブサイト
そこでひらめきました。このResult Builderを活用して、動的なサイトを構築できるのではないかということです。
CGIの考え方を応用
仕組みはこうです。その昔から今もありますが、ApacheのようなウェブサーバーにはCGIをのせる仕組みがあります。URLから /path/to/hello.cgi のようにCGIの実行モジュールを呼び出すと、Cなどで書かれた実行コードでHTMLなどを生成できます。
このCGIに相当するものをSwiftで書いて、それがDSLでHTML風に書ければ、サイト全体をビルドするのではなく、HTMLでいうページ単位をSwiftで書けるのではないかという発想です。
http://example.com/hello/world/index.html の代わりに
http://example.com/hello/world/index.swift を実行してHTMLを生成するイメージです。
ただ、Swiftのソースが呼ばれても困るので、Swiftでコンパイル済みの index という実行可能コードを起動してHTMLを生成させます。やっぱり、ただのCGIですね。
さらに言ってしまえば、C++や他の言語でも可能ですが、DSLでHTMLっぽく書こうとするとSwiftは美しく実装できそうです。
アーキテクチャ
ディレクトリ構造
そのまま、パスの先に .swift があっても仕方ないので、src と web に分けます。Swiftでサイトを作る時は、src の下にHTMLに相当するSwiftコードを書きます。
サイトのコーディングが終わったらビルドします。ビルドは src/ のディレクトリ構造を基に web/ と bin/ を構築します。src/ 下の .swift ソースはビルドされて、bin/ の相当する場所に実行コードを配置します。
例: src/docs/index.swift → コンパイル → bin/docs/index + web/docs/index.webbin
site-root/
├── src/ # Swiftソースファイル
│ ├── index.swift # ホームページルート
│ ├── about.swift # Aboutページルート
│ └── docs/
│ └── index.swift # Docsインデックスルート
├── web/ # 静的ファイル + .webbinマーカー
│ ├── styles/ # CSSファイル
│ ├── *.webbin # ルートマーカー(自動生成)
│ └── images/ # 静的アセット
└── bin/ # コンパイル済み実行ファイル(自動生成)
├── index # / 用の実行ファイル
├── about # /about 用の実行ファイル
└── docs/
└── index # /docs 用の実行ファイル
Webサーバーの仕組み
Apacheなどでもできるのかもしれませんが、Webの知識は門外漢なのと、やらせたいことがやや特殊なので、独自に開発することにしました。
リクエスト処理フロー
-
/docs/indexが呼ばれます - ウェブサーバーは
site-root/web/docs/index.webbinを探します -
.webbinがあれば、実行コードが存在する証となります -
site-root/bin/docs/indexの実行コードを起動します - HTMLを生成してブラウザにレスポンスします
静的ファイルの処理
ウェブサーバーはパスの先が仮に .jpg や .css などのリソースであれば、そのまま web/ 下にあるリソースを返します。
これを実現するためには独自のウェブサーバーを開発したり、独自の複雑なビルドの仕組みが必要ですが、構造自体はシンプルです。
実際のコード例
基本的なページ
index.html に相当する index.swift はこんな感じで書きます。SwiftUIっぽいコードだと気がつくと思います。
// src/index.swift
import Swiftlets
@main
struct HomePage: SwiftletMain {
var title = "Ben's Portfolio"
var body: some HTMLElement {
VStack(spacing: 20) {
H1("Hello, I'm Ben! 👋")
P("iOS Developer. Swift Enthusiast.")
}
}
}
プロパティラッパーの活用
リクエストにクエリパラメータが含まれている場合やCookieを扱う場合は、以下のような書き方をします。
@Query("name") var userName: String?
@Cookie("theme", default: "light") var theme: String? // デフォルト値を指定
SwiftUIの @State や @Binding と同じような感覚で使えます。
クイックスタート
ビルドと実行
# サイトをビルド
./build-site sites/my-site
# サーバーを起動
./run-site sites/my-site
# ブラウザでアクセス
open http://localhost:8080
ホットリロード
開発中はサーバーを起動したまま、変更したルートだけ再ビルドできます。サーバーの再起動は不要です!
# サイトを再ビルド(サーバーは起動したまま)
./build-site sites/my-site
変更された実行ファイルは自動的に置き換わり、次のリクエストから新しいコードが実行されます。これにより、開発サイクルが非常に快適になります。
他のフレームワークとの比較
SwiftletsはVaporやKituraとは異なるアプローチを取っています:
| 特徴 | Swiftlets | Vapor/Kitura |
|---|---|---|
| アーキテクチャ | ルートごとのプロセス | 単一サーバープロセス |
| ホットリロード | ✅ ルート単位で可能 | ⚠️ サーバー再起動必要 |
| HTML生成 | SwiftUI風DSL | テンプレートエンジン |
| 学習曲線 | SwiftUI経験者に優しい | Web開発の知識が必要 |
| 用途 | 中小規模サイト | 大規模API・アプリ |
Vaporは大規模なRESTful APIや複雑なWebアプリに向いていますが、SwiftletsはよりシンプルでSwiftUIライクな体験を提供します。
Linuxでの実行
SwiftletsはLinuxのSwiftでビルド・実行可能です。ただ、Linuxのバージョンによっては要求されるSwiftのバージョンが用意できない可能性もあるので注意が必要です。
当方ではAWSのUbuntu Linuxでデモサイトのビルドと実行に成功しています。
デモサイト: http://swiftlet.eastlynx.com:8080
制限事項と適した用途
現在の制限事項
Swiftletsは実験的なプロジェクトであり、以下の制限があります:
- ⚠️ パフォーマンス: プロセス起動のオーバーヘッド(数ms〜十数ms)があります
- ⚠️ 開発段階: まだ発展途上です。プロダクション利用は慎重にご検討ください
- ⚠️ コミュニティ: まだ小さいです。ドキュメントや事例も増やしていく段階です
- ⚠️ セッション管理: 現在はCookieとファイルベースのストレージで対応(将来的に改善予定)
- ⚠️ データ永続化: 各ルートが独立したプロセスなので、共有データはファイルやDBで管理する必要があります
状態管理について: 各リクエストが独立したプロセスなので、メモリ上の状態共有はできません。セッションデータやユーザー情報は、Cookieやファイルストレージ、外部データベース(SQLiteなど)を使って管理します。
想定される用途 ✅
- 個人のポートフォリオサイト
- 技術ブログやドキュメントサイト
- 中小規模のWebアプリケーション
- SwiftUIの知識を活かしたいプロジェクト
- プロトタイピング・実験的な開発
想定されていない用途 ❌
- 超高トラフィックのサービス(プロセスオーバーヘッドが問題になる可能性)
- ミリ秒単位のレスポンスが求められるリアルタイムシステム
- 複雑なマイクロサービスアーキテクチャ(Vaporの方が適している)
- エンタープライズ向け本格運用(現時点では試験的)
まとめ
SwiftでWebサイトを構築するという発想は、一見突飛に見えるかもしれません。しかし、以下のようなメリットがあります:
- ✅ 型安全: コンパイル時にエラーを検出できる
- ✅ SwiftUIライクな書き心地: iOSデベロッパーには馴染みやすい
- ✅ シンプルな仕組み: CGIの考え方をモダンに再実装
- ✅ クロスプラットフォーム: macOSでもLinuxでも動作
- ✅ プロセス分離: 1つのルートのクラッシュが他に影響しない
- ✅ ホットリロード: サーバー再起動なしで開発できる
まだまだ発展途上のプロジェクトですが、Swiftでサーバーサイド開発をしたい方、興味のある方はぜひ試してみてください。フィードバックやコントリビューションも大歓迎です!