HTMXでリアルタイムWebアプリ開発!htmx.createWebSocket徹底解説


WebSocket は、HTTP 要求/応答モデルとは異なり、サーバーとクライアント間で永続的な接続を維持し、双方向にメッセージをやり取りすることができます。これにより、チャットアプリケーションやリアルタイムデータ更新など、低遅延で双方向性の高い通信が必要なアプリケーションに最適です。

htmx.createWebSocket を使用すると、以下の利点が得られます。

  • 軽量
    WebSocket プロトコルは軽量で、HTTP 要求/応答モデルよりも少ないオーバーヘッドで通信することができます。
  • 双方向通信
    サーバーとクライアント間で双方向にメッセージをやり取りすることができます。
  • 低遅延
    HTTP 要求/応答モデルよりも低遅延で通信することができます。
  • リアルタイム通信
    サーバーからのメッセージを即座に受信し、クライアントからサーバーへメッセージを即座に送信することができます。

使い方

htmx.createWebSocket は、以下の引数を取ります。

  • options
    オプションの設定 (例: ヘッダー、プロトコルバージョン)
  • url
    WebSocket サーバーの URL
const socket = htmx.createWebSocket('ws://localhost:8080', {
  headers: {
    Authorization: 'Bearer my-token',
  },
});

socket.onmessage = (event) => {
  console.log('Received message:', event.data);
};

socket.onopen = () => {
  console.log('WebSocket connection opened');
};

socket.onerror = (event) => {
  console.error('WebSocket error:', event.error);
};

socket.send('Hello from HTMX!');
  • WebSocket 接続は、セキュリティ上の理由から、HTTPS 接続でのみ使用できます。
  • WebSocket 接続は、ブラウザが閉じられたり、ページが再読み込みされたりすると切断されます。
  • htmx.createWebSocket は、WebSocket 接続を確立するだけで、メッセージの送受信は onmessagesend などのイベントハンドラを使用して行う必要があります。


HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>チャットアプリケーション</title>
  <script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
  <h1>チャット</h1>

  <div id="messages">
    </div>

  <input type="text" id="message-input" placeholder="メッセージを入力">
  <button id="send-button">送信</button>

  <script>
    const socket = htmx.createWebSocket('ws://localhost:8080');

    socket.onmessage = (event) => {
      const message = JSON.parse(event.data);
      const messageElement = document.createElement('div');
      messageElement.textContent = `${message.user}: ${message.message}`;
      document.getElementById('messages').appendChild(messageElement);
    };

    document.getElementById('send-button').onclick = () => {
      const message = document.getElementById('message-input').value;
      const messageData = {
        user: 'あなた',
        message: message,
      };
      socket.send(JSON.stringify(messageData));
      document.getElementById('message-input').value = '';
    };
  </script>
</body>
</html>

サーバーコード (Python)

import asyncio
import websockets

async def handle_connection(websocket, path):
  while True:
    try:
      data = await websocket.recv()
      message = json.loads(data)
      print(f'Received message: {message}')

      # メッセージを他の接続にブロードキャスト
      for other_websocket in ws_server.websockets:
        if other_websocket != websocket:
          await other_websocket.send(json.dumps(message))
    except Exception as e:
      print(f'Error: {e}')
      break

ws_server = websockets.WebSocketServer('localhost', 8080)

async def main():
  async with ws_server:
    await asyncio.gather(*[handle_connection(ws, path) for ws, path in ws_server.websockets])

if __name__ == '__main__':
  asyncio.run(main())

説明

  • サーバーコード (Python) では、WebSocket 接続を処理し、メッセージを他の接続にブロードキャストするコードが含まれています。
  • HTML コードでは、WebSocket 接続を確立し、メッセージの送受信を処理する JavaScript コードが含まれています。

例 2: リアルタイムデータ更新

この例では、htmx.createWebSocket を使用して、サーバーからリアルタイムでデータを受信し、Web ページを更新します。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>リアルタイムデータ更新</title>
  <script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
  <h1>リアルタイムデータ</h1>

  <div id="data">
    </div>

  <script>
    const socket = htmx.createWebSocket('ws://localhost:8080');

    socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      document.getElementById('data').textContent = data.value;
    };
  </script>
</body>
</html>
import asyncio
import random
import time
import websockets

async def handle_connection(websocket, path):
  while True:
    try:
      # ランダムな数値を生成して送信
      value = random.randint(0, 100)
      data = {
        'value': value,
      }
      await websocket.send(json.dumps(data))

      # 1 秒待ってから送信を繰り返す
      await asyncio.sleep(1)
    except Exception as e:
      print(f'Error: {e}')
      break

ws_server = websockets.


代替方法

  • サードパーティライブラリ
    • Primus (WebSocket communication for JavaScript)
    • SockJS (JavaScript library for real-time communication with web servers)
  • WebSocket API
    • WebSocket クラス (ブラウザ標準 API)
    • ReconnectingWebSocket (Reconnecting WebSocket for JavaScript library)

各方法の詳細と比較

方法利点欠点適用例
htmx.createWebSocketHTMX との統合が簡単機能が限られているシンプルなチャットアプリケーション
WebSocket API柔軟性と制御性が高いコード量が多くなるより複雑なリアルタイムアプリケーション
ReconnectingWebSocket自動的に再接続設定が必要接続が途切れた場合でもリアルタイム性を維持したい場合
Primus使いやすく、高度な機能を備えているhtmx との統合が難しい複雑なリアルタイムアプリケーション
SockJS多くのブラウザで動作古いブラウザではサポートされていない可能性があるブラウザ互換性が重要

具体的な代替方法の例

WebSocket API

const socket = new WebSocket('ws://localhost:8080');

socket.onmessage = (event) => {
  console.log('Received message:', event.data);
};

socket.onopen = () => {
  console.log('WebSocket connection opened');
};

socket.onerror = (event) => {
  console.error('WebSocket error:', event.error);
};

socket.send('Hello from HTMX!');

ReconnectingWebSocket

const socket = new ReconnectingWebSocket('ws://localhost:8080');

socket.onmessage = (event) => {
  console.log('Received message:', event.data);
};

socket.onopen = () => {
  console.log('WebSocket connection opened');
};

socket.onerror = (event) => {
  console.error('WebSocket error:', event.error);
};

socket.send('Hello from HTMX!');

Primus

const primus = Primus('ws://localhost:8080');

primus.on('open', () => {
  console.log('WebSocket connection opened');
});

primus.on('data', (data) => {
  console.log('Received message:', data);
});

primus.on('error', (error) => {
  console.error('WebSocket error:', error);
});

primus.send('Hello from HTMX!');

SockJS

const sockjs = new SockJS('http://localhost:8080/sockjs/endpoint');

sockjs.onopen = () => {
  console.log('WebSocket connection opened');
};

sockjs.onmessage = (data) => {
  console.log('Received message:', data);
};

sockjs.onerror = (error) => {
  console.error('WebSocket error:', error);
};

sockjs.send('Hello from HTMX!');

htmx.createWebSocket は、シンプルで使いやすい WebSocket 接続確立のための便利な機能ですが、状況によっては他の方法の方が適切な場合があります。

  • ブラウザ互換性
    SockJS を選択
  • 高度な機能
    Primus を選択
  • 自動再接続
    ReconnectingWebSocket を選択
  • 柔軟性と制御性
    WebSocket API を選択
  • シンプルさ
    htmx.createWebSocket を選択