エッジコンピューティング入門 - Cloudflare Workersで作るサーバーレスアプリ
エッジコンピューティングは、ユーザーに最も近い場所でコードを実行する新しいパラダイムです。Cloudflare Workersを使って、0msコールドスタートのグローバルアプリケーションを構築する方法を解説します。
htmxは最小限のJavaScriptで高度なインタラクティブ機能を実現するライブラリです。SPAの複雑さに疲れた開発者に向けて、HTMLの拡張によるシンプルで保守しやすいWeb開発手法を解説します。
モダンな web 開発において、SPA フレームワークの複雑さに悩まされていませんか? htmx は「html を拡張する」というシンプルなアプローチで、複雑な javascript フレームワークなしに高度なインタラクティブ機能を実現します。 本記事では、htmx 2.0 の最新機能を含め、実践的な使い方を詳しく解説します。
2025 年、多くの開発者が SPA フレームワークの複雑さに疲弊しています。 ビルド設定、状態管理、ルーティング、バンドルサイズ…本当にこれらすべてが必要でしょうか?
チャートを読み込み中...
htmx が提供する価値:
なぜ
<a>
と<form>
だけが HTTP リクエストを送れるのか? この制約を取り除くことで、html は真のハイパーテキストになる。
ハイパーメディア駆動開発(Hypermedia-Driven Development)は、 アプリケーションの状態をサーバー側で管理し、html を通じてクライアントに伝える開発手法です。
概念 | REST API | HATEOAS with htmx |
---|---|---|
データ形式 | JSON | HTML |
状態管理 | クライアント | サーバー |
次のアクション | クライアントが決定 | サーバーが提供 |
複雑さ | 高い | 低い |
htmx は、html 要素に属性を追加するだけで Ajax 機能を実現します。 基本的な属性を理解すれば、すぐに使い始められます。
<!-- htmx 2.0をCDNから読み込み -->
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<!-- 基本的な使い方 -->
<button hx-post="/clicked"
hx-target="#result"
hx-swap="innerHTML">
クリックしてください
</button>
<div id="result">
<!-- ここにサーバーからのレスポンスが挿入される -->
</div>
属性 | 説明 | 使用例 |
---|---|---|
hx-get | GET リクエストを送信 | hx-get="/users" |
hx-post | POST リクエストを送信 | hx-post="/users/new" |
hx-trigger | トリガーイベントを指定 | hx-trigger="click" |
hx-target | 更新対象の要素を指定 | hx-target="#content" |
hx-swap | 更新方法を指定 | hx-swap="outerHTML" |
hx-indicator | ローディング表示 | hx-indicator="#spinner" |
<!-- 様々なトリガーの例 -->
<!-- 入力の500ms後に検索 -->
<input type="text"
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results">
<!-- スクロールで追加読み込み -->
<div hx-get="/more-content"
hx-trigger="revealed"
hx-swap="afterend">
さらに表示...
</div>
<!-- 定期的な更新 -->
<div hx-get="/notifications"
hx-trigger="every 30s"
hx-swap="innerHTML">
通知エリア
</div>
実際のアプリケーションでよく使用されるパターンを紹介します。
<form hx-post="/contact"
hx-target="#form-container"
hx-swap="outerHTML">
<div class="form-group">
<label>名前</label>
<input type="text" name="name" required>
</div>
<div class="form-group">
<label>メールアドレス</label>
<input type="email" name="email" required>
</div>
<div class="form-group">
<label>メッセージ</label>
<textarea name="message" required></textarea>
</div>
<button type="submit">送信</button>
<!-- ローディング表示 -->
<div class="htmx-indicator" id="spinner">
送信中...
</div>
</form>
サーバー側のレスポンス例(エラー時):
<form hx-post="/contact" hx-target="#form-container">
<div class="alert alert-error">
メールアドレスが正しくありません
</div>
<!-- フォームの内容を保持して返す -->
</form>
<!-- 削除ボタン -->
<tr id="user-123">
<td>山田太郎</td>
<td>yamada@example.com</td>
<td>
<button hx-delete="/users/123"
hx-target="#user-123"
hx-swap="outerHTML swap:1s"
hx-confirm="本当に削除しますか?">
削除
</button>
</td>
</tr>
<!-- インライン編集 -->
<div id="user-name-123" class="editable">
<span hx-get="/users/123/edit"
hx-trigger="click"
hx-target="#user-name-123">
山田太郎
</span>
</div>
<!-- 編集フォーム(サーバーから返される) -->
<div id="user-name-123">
<input type="text"
value="山田太郎"
hx-put="/users/123"
hx-trigger="blur"
hx-target="#user-name-123">
</div>
<!-- ドラッグ&ドロップで並び替え -->
<ul hx-post="/tasks/reorder"
hx-trigger="end"
hx-vals='js:{order: getTaskOrder()}'>
<li draggable="true" data-task-id="1">
タスク1
</li>
<li draggable="true" data-task-id="2">
タスク2
</li>
<li draggable="true" data-task-id="3">
タスク3
</li>
</ul>
<div id="posts">
<!-- 最初の投稿リスト -->
<article>投稿1</article>
<article>投稿2</article>
<!-- ... -->
<!-- 次のページを読み込むトリガー -->
<div hx-get="/posts?page=2"
hx-trigger="revealed"
hx-swap="outerHTML"
hx-indicator="#loading-spinner">
<div id="loading-spinner" class="htmx-indicator">
読み込み中...
</div>
</div>
</div>
htmx の大きな利点は、javascript が無効でも基本機能が動作することです。
<!-- JavaScriptが無効でも動作するフォーム -->
<form method="post" action="/search"
hx-post="/search"
hx-target="#results"
hx-push-url="true">
<input type="search" name="q" placeholder="検索...">
<button type="submit">検索</button>
</form>
<div id="results">
<!-- 検索結果がここに表示される -->
</div>
htmx はサーバーサイドの言語やフレームワークを選びません。 どんなバックエンドとも連携できます。
# Python/Flask の例
from flask import Flask, render_template, make_response
@app.route('/users/<int:id>', methods=['DELETE'])
def delete_user(id):
# ユーザーを削除
User.delete(id)
# htmx用のレスポンスヘッダー
response = make_response("", 200)
response.headers['HX-Trigger'] = 'userDeleted'
response.headers['HX-Redirect'] = '/users'
return response
<!-- クライアント側でイベントを受信 -->
<script>
document.body.addEventListener('userDeleted', function(evt) {
// トースト通知を表示
showToast('ユーザーが削除されました');
});
</script>
htmx と Alpine.js を組み合わせることで、必要最小限のクライアントサイドロジックを追加できます。
<!-- Alpine.jsでUI状態を管理 -->
<div x-data="{ open: false, count: 0 }">
<button @click="open = !open">
メニューを開く
</button>
<div x-show="open" x-transition>
<ul hx-get="/menu-items"
hx-trigger="revealed once">
<!-- メニュー項目がサーバーから読み込まれる -->
</ul>
</div>
<!-- カウンターはクライアント側で管理 -->
<button @click="count++"
hx-post="/track-click"
hx-vals='js:{count: count}'>
クリック数: <span x-text="count"></span>
</button>
</div>
htmx を使用したアプリケーションのパフォーマンス特性を見てみましょう。
同じ機能を持つダッシュボードアプリケーションでの比較
チャートを読み込み中...
実際のプロジェクトで htmx を活用した例を紹介します。
<div class="dashboard">
<!-- サイドバー -->
<nav class="sidebar">
<a href="/dashboard"
hx-get="/dashboard/overview"
hx-target="#main-content"
hx-push-url="true">
概要
</a>
<a href="/dashboard/users"
hx-get="/dashboard/users"
hx-target="#main-content"
hx-push-url="true">
ユーザー管理
</a>
<a href="/dashboard/settings"
hx-get="/dashboard/settings"
hx-target="#main-content"
hx-push-url="true">
設定
</a>
</nav>
<!-- メインコンテンツ -->
<main id="main-content">
<div hx-get="/dashboard/overview"
hx-trigger="load">
<!-- 初期コンテンツ -->
</div>
</main>
<!-- リアルタイム通知 -->
<div hx-ext="sse"
sse-connect="/notifications"
hx-trigger="sse:notification">
<div id="notification-area"></div>
</div>
</div>
<div class="product-listing">
<!-- フィルター -->
<aside class="filters">
<form hx-get="/products"
hx-target="#product-grid"
hx-trigger="change">
<h3>カテゴリー</h3>
<label>
<input type="checkbox" name="category" value="electronics">
電化製品
</label>
<label>
<input type="checkbox" name="category" value="clothing">
衣類
</label>
<h3>価格帯</h3>
<input type="range"
name="max_price"
min="0"
max="100000"
hx-trigger="change throttle:500ms">
<h3>並び順</h3>
<select name="sort">
<option value="newest">新着順</option>
<option value="price_asc">価格が安い順</option>
<option value="price_desc">価格が高い順</option>
</select>
</form>
</aside>
<!-- 商品グリッド -->
<div id="product-grid" class="products">
<!-- 商品一覧 -->
</div>
</div>
450行のJavaScript、3つの状態管理
50行のHTML属性、状態管理不要
保守性も大幅向上
htmx は万能ではありません。適している場面と適さない場面を理解して使用しましょう。
用途 | 適合度 | 理由 |
---|---|---|
管理画面・ダッシュボード | ★★★★★ | CRUD操作が中心でSEO不要 |
ECサイト | ★★★★★ | SEO重要、サーバー側で商品管理 |
ブログ・CMS | ★★★★★ | コンテンツ中心、高速表示 |
社内ツール | ★★★★★ | 開発速度重視、複雑なUI不要 |
フォーム中心のアプリ | ★★★★☆ | バリデーションをサーバー側で統一 |
「アプリケーションの状態をどこで管理すべきか」を考えましょう。 サーバー側で管理できる場合、htmx は素晴らしい選択肢になります。
htmx は「シンプルさ」と「パワフルさ」を両立する、新しい web 開発のパラダイムです。 SPA の複雑さに疲れたら、ぜひ htmx を試してみてください。
htmx を採用してから、新機能の実装速度が 3 倍になりました。 コードベースもシンプルになり、新しいメンバーもすぐに開発に参加できます。