a-blog cms 3.2 で htmx を標準サポートすることになりました
まだ正式版 Ver. 3.2 リリース前ですが、今日は「ハイパーメディアシステム──htmxとRESTによるシンプルで軽やかなウェブ開発」の発売日という事もあるので htmx の記事を書いてみる事にしました。
a-blog cms Ver. 3.2 で htmx を標準サポートする事になりました。
Ver. 3.1 までの htmx 対応について
Ver. 3.1 までは、以下のような JavaScript を <head> 内に事前に記述しておく必要がありました。htmx を活用する際に、どのような準備が必要だったのか、今後の参考のためにも記録しておきます。
htmx 本体の読み込み
htmx を実行するためには、ライブラリ本体が必要です。テスト時は CDN からの読み込みでも問題ありませんが、本番運用ではセキュリティや可用性の観点から自社サーバーへ設置することを推奨します。
<script src="/themes/htmx@blog/js/htmx.mim.js?date=20241228155737"></script>
htmx のカスタム設定
historyCacheSize = -1 : htmx は通常、ブラウザの「戻る・進む」操作時にキャッシュしたページ断片を再利用しますが、CMSの状態や認証等でキャッシュが問題になることが多く、必ず最新の内容を取得するためにキャッシュを無効化しています。
refreshOnHistoryMiss = true : キャッシュに無い場合は自動的にページを再取得します。
<script> htmx.config.historyCacheSize = -1; htmx.config.refreshOnHistoryMiss = true; </script>
ヒストリーAPI用URL整形
ヒストリーAPI に記録する URL に /tpl を含むものを記録しないようにするために、/include/htmx/ が含まれる際には include/htmx/filename.html を削除するような処理を追加しています。
<script> addEventListener('htmx:beforeHistoryUpdate', function (event) { const proposedUrl = event.detail.history.path; let customUrl = proposedUrl; if (proposedUrl.includes('/include/htmx/')) { customUrl = proposedUrl.replace(/\/include\/htmx\/.*\.html/, ''); } event.detail.history.path = customUrl; }); </script>
CSRFトークンの自動付与
a-blog cms では <form> のタグでは自動で CSRFトークンのタグが自動挿入されますので hx-post には必要ないのですが、hx-get の際にも CSRFトークンを利用可能にするための設定になります。
<script> document.addEventListener("htmx:configRequest", function(event) { const csrfToken = document.querySelector('meta[name="csrf-token"]').content; event.detail.headers['X-CSRF-Token'] = csrfToken; }); </script>
htmx 実行後の acms.js 再実行
htmx を利用し Ajax でコンテンツを読み込んできた部分の HTML で a-blog cms で用意している JavaScript ( acms.js ) が必要な時に再度実行させます。
<script> addEventListener('htmx:afterSwap', function (event) { ACMS.Dispatch(event.target); }); </script>
Ver. 3.2 以降の htmx 対応について
上記の事前準備的な設定が必要なくなりました。
hx-get や hx-post などの属性を HTML に記述するだけで、自動的に必要な環境が準備されます。
従来は class="js-post_include" のような記述で Ajax コンテンツの読み込みを実現していましたが、今後は hx-post への置き換えにより、より柔軟かつ高度な制御が可能になります。さらに hx-get を利用することで、<a> タグでも Ajax 読み込みが可能となります。
hx-post & hx-push-url の利用の際(ヒストリーAPI 用 URL 整形)
hx-get の場合は hx-push-url="{url}" を設定することで問題ありませんが、hx-post の場合はテンプレートで事前に ヒストリー API に登録する URL を決めることができません。そこで、必要なタイミングでのみ ヒストリー API 用 URL 整形処理を実行できるようにしています。
hx-post & hx-push-url を利用する場合は、テンプレートファイル内の任意の場所に data-acms-hx-push-url 属性を追加してください。値は不要です。
<article class="entry" data-acms-hx-push-url> ... </article>
htmx の実装について
基本的な属性の設定
<a href="{url}"> を以下のように hx-属性 を追加します。
htmx のポイントは、hx-get の URL を「取得したいコンテンツのパス(通常は /tpl/ 配下)」に指定する点です。
一般的には hx-push-url="true" としますが、true の場合は tpl を含む URL が履歴に残ってしまうため、hx-push-url="{url}" のように本来の URL を明示的に指定します。
<a href="{url}" hx-get="{url}/tpl/include/entry-body.html" hx-push-url="{url}" hx-swap="innerHTML" hx-target="#main-contents">
テンプレートの設定
まず _entry.html と entry-body.html の記述方法を理解できれば、他のテンプレートも同様に記述できます。
_entry.html
全体は割愛しますが、entry-body.html をインクルードする際は変数 multi_swap : off に設定します。
@include("/include/entry-body.html" , {"multi_swap" : "off"})
entry-body.html
通常は Entry_Body のみを記述しますが、このテンプレートでは「トピックパス」やタイトルタグの書き換えも同時に行えるように設計します。
<!-- BEGIN_IF [{{multi_swap}}/neq/off] --> の指定により、_entry.html からの読み込み時には非表示にし、htmx での呼び出し時のみ表示させるよう分岐します。
また、hx-swap-oob="true" の指定により、id="topicpath" のエリアを置き換えることができます。
<!-- BEGIN_MODULE Entry_Body id="entry_body" --> (内容は省略) <!-- END_MODULE Entry_Body --> <!-- BEGIN_IF [{{multi_swap}}/neq/off] --> <!-- BEGIN_MODULE Topicpath id="topicpath" hx-swap-oob="true" --> (内容は省略) <!-- END_MODULE Topicpath --> <!-- BEGIN_MODULE Ogp --> <title>{title}</title> <!-- END_MODULE Ogp --> <!-- END_IF -->
最後に
X.com で #ablogcms を検索してみたところ、嬉しい POST を発見したのでご紹介します。この最初に紹介した本を読んだ方が、「a-blog cms の開発者向けドキュメントを読んでいるような気分になってきた」と感想を書いてくれていました。
htmx本、4割くらい読み進めて具体的な実装例が紹介され始めて、#ablogcms の開発者向けドキュメント読んでるような気分になってきた。ポストインクルードみがすごい。
— sunami hokuto (@shokuto) June 11, 2025
a-blog cms をバックエンドに使うことで、バックエンド側を何も書かないで htmx をサクサク利用できるようになります。 ぜひ、ablogcms.io でお試しを!