Monacaアプリを作る際に欠かせないのがサーバーとの通信でしょう。この時にはいわゆるAjaxと呼ばれる手法を利用して、サーバーへリクエストを行い、返ってきたレスポンスに応じて画面を書き換えます。

こうした処理を書くのはとても面倒で、複雑になりやすいものです。そこで使ってみたいのがhtmxになります。htmxはJavaScriptを書かずにサーバーとの通信処理を実現できるライブラリになります。

本記事ではhtmxの使い方を簡単なコードを交えつつ紹介します。

htmxとは

htmxは前述の通り、JavaScriptを書かずにネットワーク通信や高度なUXを実現できるライブラリになります。

htmxは、HTMLタグの属性を使用してHTML内で直接AJAX、CSSトランジション、WebSockets、およびサーバー送信イベントにアクセスできるようにします。

htmxを使うことで、面倒な(かつ毎回同じような)JavaScriptを書かずに済み、エラーハンドリングなどを含めてhtmxがすべてハンドリングしてくれるようになります。

htmxのインストール

htmxのインストールは幾つか用意されています。まず手軽なのはCDNを利用した方法でしょう。

<script src="https://unpkg.com/htmx.org@1.8.6" integrity="sha384-Bj8qm/6B+71E6FQSySofJOUjA/gq330vEqjFx9LakWybUySyI1IQHwPtbTU7bNwx" crossorigin="anonymous"></script>

次にCDN配信されているJavaScriptファイルをダウンロードして、アプリで読み込む方法です。

<script src="js/htmx.min.js"></script>

htmxの例

htmxでAjaxを書く処理を想定します。通常ですと、以下のように書きます。今回は単純化していますが、実際にはリクエスト内容を作ったり、認証があったりともっと複雑でしょう。

次のコードは、デモサーバーとしてサービス"JSONPlaceholder"を利用しています。

※ JSONPlaceholderは、JSONのダミーデータを提供する無料オンラインREST APIです。GET、POST、PUT、PATCH、DELETEの操作を実行でき、テストやプロトタイピングに利用することができます。

<a href="#" onclick="ajax">クリック</a>
<div id="result">結果</div>
<script>
  async function ajax() {
    const result = document.querySelector("#result");
    try {
      const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
      result.innerHTML = await res.text();
    } catch (e) {
      result.innerHTML = e.message;
    }
  }
</script>

この処理をhtmxで書くと次のようになります。JavaScriptは一切書かず、HTMLタグの要素で指定するだけです。

<a href="#" hx-get="https://jsonplaceholder.typicode.com/todos/1" hx-trigger="click" hx-target="#result">
    Click here to load content
</a>

<div id="result">Loading...</div>

htmxでできること

htmxには以下のような機能があります。

Ajax

サーバーとの通信です。HTTP GET/POST/PUT/PATCH/DELETEメソッドをサポートしています。

以下の例の場合、 div タグをクリックすると PUT /messages リクエストを行い、返ってきたレスポンスで div タグの内容を書き換えます。

<div hx-put="/messages">
    Put To Messages
</div>

ページの置き換え

htmxを利用すると、全体のHTMLを再読み込みすることなく、bodyタグ内の内容だけを書き換えることが可能です。これはRuby on Railsを活用したHotwireと似た機能を持っています。この機能により、一般的なWebサイトがシングルページアプリケーション(SPA)のようなインタラクティブ性を持つ形に進化させることができます。

このプロセスを効率的に行うためには、hx-push-url="true"を指定することを推奨します。これにより、History APIを利用することが可能となり、URLの動的な書き換えやブラウザのバックボタンの使用などが可能になります。

<div hx-boost="true">
  <a hx-get="/blog" hx-push-url="true">Blog</a>
</div>

サーバーとの通信: Ajax、SSE、WebSocketの活用

htmxを利用すれば、サーバーとの通信手段として、AjaxだけでなくSSE(Server-Sent Events)やWebSocketも選択肢となります。

例えば、チャットのようなメッセージ受信機能を実装する場合、以下のようなコードが用いられます。

<div hx-ws="connect:wss:/chatroom">
    <div id="chat_room">
        ...
    </div>
    <form hx-ws="send:submit">
        <input name="chat_message">
    </form>
</div>

この例では、hx-ws=connect: でWebSocketサーバーへの接続先を指定し、hx-ws=send: でメッセージ送信のための情報を設定しています。

また、SSEを利用することで、サーバーからの一方通行のメッセージを受け取ることも可能です。これはWebSocketとは違い、サーバーからのみメッセージが送られます。以下のように記述します。

<body hx-sse="connect:/news_updates">
    <div hx-trigger="sse:new_news" hx-get="/news"></div>
</body>

これらのコードは、ページのロードなしに動的なコンテンツ更新を行っています。

トリガーハンドリング

htmxでは、いくつかのデフォルトイベントトリガーが設定されています。それらは以下のとおりです。

  • input/textarea/select
    onchange イベント
  • form
    submit イベント
  • その他のタグ
    click イベント

これら以外のイベントをトリガーとして設定したい場合には、hx-trigger 属性を使用して指定します。例えば、次のようなコードでマウスエンターイベントをトリガーとすることができます:

<div hx-post="/mouse_entered" hx-trigger="mouseenter">
    [Here Mouse, Mouse!]
</div>

このコードは、マウスが特定の要素に入ったとき(mouseenterイベントが発生したとき)に、"/mouse_entered"へのPOSTリクエストを送信します。これにより、Webページはユーザーの操作によりダイナミックに反応することができ、より良いユーザーエクスペリエンスを提供することが可能となります。

バリデーション

htmxでは基本的にHTML5 Validation APIを利用することが推奨されていますが、カスタマイズしたバリデーションを実装したいこともあるでしょう。

その場合にはちょと複雑ですがJavaScript風に記述した入力値の検証が可能です。

<form hx-post="/test">
    <input _="on htmx:validation:validate
                if my.value != "foo"
                    call me.setCustomValidity("Please enter the value foo")
                else
                    call me.setCustomValidity("")"
        name="example"
    >
</form>

コンテンツの書き換え方

htmxではコンテンツの書き換え方も指定可能で、デフォルトではinnerHTMLが用いられます。この書き換え方はhx-swapで指定します。以下にいくつかのオプションを示します。

名称 内容
innerHTML デフォルト。コンテンツをターゲット要素の内部に配置
outerHTML 対象要素全体を返された内容で置き換え
afterbegin ターゲット内の最初の子の前にコンテンツを追加
beforebegin ターゲットの親要素でターゲットの前にコンテンツを追加
beforeend ターゲット内の最後の子の後にコンテンツを追加
afterend ターゲットの親要素でターゲットの後にコンテンツを追加
delete レスポンスに関係なく、対象要素を削除
none レスポンスからコンテンツを追加しない(帯域外のスワップやレスポンスヘッダーは処理されます)

書き方は以下のようになります。

<button hx-post="/clicked"
    hx-trigger="click"
    hx-target="#parent-div"
    hx-swap="outerHTML"
>
    Click Me!
</button>

htmxの機能拡張

htmxには機能拡張という仕組みがあります。 hx-ext という要素を使って、独自の拡張を作成できます。この拡張はJavaScriptで記述しますが、</> htmx - Extensions には様々な拡張が紹介されています。以下は機能拡張の作り方です。

まずJavaScriptで機能拡張を定義します。


htmx.defineExtension("my-ext", { onEvent : function(name, evt) { console.log("Fired event: " + name, evt); } });

この機能拡張は <div hx-ext="my-ext" /> で利用できます。

デザインパターン

ここまででhtmxの基本的な使い方は分かったと思いますが、実際にどのような場合に使えるのかを考えてみます。多くの場合において、サーバー側にほとんどのデータがあり、クライアント側でステータスを管理しない場合に有効そうです。

1. シンプルなAjaxの活用

htmxは複雑なAjax処理の実行には必ずしも適していません。それよりは、フォームからの情報送信と、その結果をユーザーインターフェース(UI)に反映する、というようなシンプルなタスクに最適です。クライアントサイドでリクエストやレスポンスの処理を行うのではなく、サーバーサイドで処理し、結果を表示するだけのアプリケーションに向いています。

2. 既存のWebサイトをSPA(シングルページアプリケーション)に変換

htmxのブースト機能を活用すると、現在表示しているHTMLのbody部分を全体的に更新することが可能です。これにより、JavaScriptやCSSの読み込み回数を削減し、Webアプリケーションのようなユーザーエクスペリエンスを効率的に実現できます。これはサーバーサイドがほとんどのコンテンツを保持し、クライアント側が表示するだけの場合に最適です。

3. チャット機能の実装

htmxはWebSocketをサポートしているため、簡単なチャットアプリケーションの実現も可能です。これは特に、チャットが主要機能ではないがチャット機能が含まれているアプリケーションに適しています。

以上の例からもわかるように、htmxはその独特の特性を活かすことで、Web開発の多様なシーンで役立つツールとなり得ます。これらのシナリオは、htmxの効率的な利用法を理解し、それを自身のプロジェクトにどのように適用するかを考えるうえでの一助となるでしょう。

まとめ

今回はhtmxというライブラリの概要を紹介しました。JavaScriptを欠かずにAjaxが実現できるので、プログラミングに不得手という方でもダイナミックな動きをするMonacaアプリが実現できるでしょう。

ぜひhtmxを使いこなして、優れたUI/UXを実現してください。