ハイパーメディア駆動アプリケーションを構築するためのGRUGスタックの使用方法

GRUG Stackは、Hypermedia-Driven Applicationsの開発に用いられる開発環境です。 HDAの開発は、HTMLという強力でモダンなREST APIで行われ、主にLocality of Behaviorの原則に基づいています。

GRUG Stackは次の要素で構成されています:

  1. Django(または他のバックエンド)
  2. TailwindCSS
  3. HTMX
  4. _hyperscript(またはAlpine.jsを好む方にはそれを使用します)

そして2つのdjangoの拡張機能:

  1. django-widget-tweaks
  2. django-render-block

このガイドでは、確認ステップがある簡易なHDA、つまりコンタクトフォームを作り方を説明します。

Github

詳しい部分に直ちに進みたい方は、このプロジェクトのGithubリポジトリ を参照してください。このガイドでは、アプリケーションのキーポイントのみをカバーしています。

ガイド

HDAでは、HTMLのようなハイパーメディアをアプリケーションの状態のエンジンとして使用します。 したがって、コンタクトフォームの主なアクション、機能とスタイリングの両方はDjangoテンプレートに含まれています。

テンプレートディレクトリのツリー構造は次の通りです:

1
2
3
4
5
6
7
8
9
core
└── templates
    └── core
        ├── base.html
        ├── contact_page.html
        └── form
            ├── _confirmation.html
            ├── _send.html
            └── contact_form.html

このプロジェクトでは、実ページ上のコンタクトフォームの使用をシミュレートしています。フォームはcontact_page.html{% included %}されます。

1
2
3
<div id="contact-form">
    {% include 'core/form/contact_form.html' %}
</div>

_send.htmlは成功メッセージのみなので、アクションは他の2つのテンプレートにあります。

ハイパーメディア駆動のアプリケーション開発におけるHTMX

HTMXは、REST APIとしてのHTMLをアップグレードするJavascriptライブラリです。これにより、開発者はJavascriptに触れることなく、複雑さを管理し、速くてセキュアなフロントエンドを簡単に構築することができます。

contact_page.htmlでは:

1
2
3
4
5
6
7
8
<form>
    ...
    <button hx-post="confirm/"
            hx-target="#contact-form"
            hx-swap="innerHTML">
        Confirm
    </button>
</form>

hx-*属性はHTMXの属性です。 フォームが送信されると、confirmエンドポイントへのPOSTリクエストが作成されます。 それは_confirmation.htmlの内容を戻します。 HTMXはその内容を取得し、contact_page.htmlでかつてフォームを包んでいた#contact-formというIDの要素のinnerHTMLと入れ替えます。

テンプレートフラグメントとの作業

現代のウェブ開発では、多くのユーザーインタラクションにおいて、ページ全体ではなくページの一部を提供する形になります。 django-render-block拡張機能は開発者がテンプレートフラグメントを容易に提供することを可能にします。

私たちのコンタクトフォームは三つのビューを通じて3つの状態にアクセスできますが、フルページをレンダリングするのはそのうちの一つだけです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from render_block import render_block_to_string


def contact_page(request: HttpRequest) -> HttpResponse:
    if request.POST:
        form = ContactForm(request.POST)
        context = {'form': form}
        block = 'contact_form'
        html = render_block_to_string("core/contact_page.html", block, context)
        return HttpResponse(html)
    form = ContactForm()
    context = {'form': form}
    return render(request, 'core/contact_page.html', context)

GETリクエスト(ナビゲーションバーのContact Usリンクをクリックするなど)が発生すると、contact_pageは完全なページをレンダリングします。 しかし、POSTリクエストを受け取ると、render_block_to_string関数を使用してテンプレートフラグメントをレンダリングします。

contact_page.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{% extends 'core/base.html' %}

{% block content %}
    <h1>Contact Form</h1>
    {% block contact_form %}
        <div id="contact-form">
            {% include 'core/form/contact_form.html' %}
        </div>
    {% endblock %}
{% endblock %}

views.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from render_block import render_block_to_string

def contact_page(request: HttpRequest) -> HttpResponse:
    if request.POST:
        form = ContactForm(request.POST)
        context = {'form': form}
        block = 'contact_form'
        html = render_block_to_string("core/contact_page.html", block, context)
        return HttpResponse(html)
    form = ContactForm()
    context = {'form': form}
    return render(request, 'core/contact_page.html', context)

contact_form.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{% block contact_form %}
<form>
 ...
    <button hx-post="confirm/"
            hx-target="#contact-form"
            hx-swap="innerHTML">
        Confirm
    </button>
</form>
{% endblock %}

Confirmボタンがクリックされたとき、confirmエンドポイントへのリクエストが作成されます。 エンドポイントはフォームを検証し、有効であれば、HTML APIで確認テンプレートを返します。 そうでない場合は、POSTリクエスト付きのcontact_pageを返します。

その場合、contact_pagecontact_page.htmlテンプレートのcontact_formブロックの内容のみとコンテキストを返します。HTMXはそれを#contact-formdivのinnerHTMLに入れ替えます。

validate_then_confirmビューとsend_formビューは、それぞれのテンプレートのcontact_formブロックの内容のみを含むHttpResponsesを返します。

django-render-blockとHTMXを使えば、テンプレートフラグメントへの直接的なパイプラインとフラグメントの入れ替え方法が使用可能になります。これらは全てJavascript一行触らずに実現することができます。

こんなに簡単に作業できるので、私のような素人でも出来ます。

そしてHTMXは、HTMLのような高度なREST APIを使ってモダンなウェブアプリケーションを構築できるようにしてくれる一方で、TailwindCSSは、同じAPIでモダンなデザインを構築できるようにします。

それがまさにハイパーメディア駆動のアプリケーション開発の本質です。

ハイパーメディア駆動のアプリケーション開発におけるTailwindCSS

TailwindCSSは、デザインシステムを実装する一連のユーティリティクラスのセットです。 HTMLエレメントのスタイル設定はローカルで行われ、「セマンティック」なクラス名で別のCSSファイルのスタイル詳細を参照することはありません。

contact_page.htmlでは:

1
2
3
{% load widget_tweaks %}
...
{% render_field field placeholder=field.label class="w-full bg-slate-200 font-normal font-body text-xl text-slate-900 border-2 border-slate-900 focus:ring-0 focus:outline-0 focus:border-cyan-500 placeholder:text-slate-500" %}

render_fieldテンプレートタグはdjango-widget-tweaksによって提供されます。 これにより、Pythonのフォーム定義でスタイルを設定する必要がある場合でも、テンプレート内でフォームをスタイリングできます。

TailwindCSSのユーティリティクラスとdjango-widget-tweaksを使用することで、開発者はすべてのスタイリング情報をREST APIに直接配置することでフロントエンドの複雑さを管理できます。

ハイパーメディア駆動のアプリケーション開発での_hyperscript

_hyperscriptもまた、HTMLをアプリケーションステートのエンジンとして使用しながらモダンなフロントエンドを構築するHDA開発者を支援するために設計されたJavascriptライブラリです。そして最高のことに、私たちはJavascriptに触れる必要がありません。

HTMXがHTTPリクエストとテンプレートフラグメントの入れ替えを扱う一方で、_hyperscriptはイベントとDOM操作を扱います。

このコンタクトフォームでは、HTML要素のクラスの切替えと別の要素の削除、という単純なアクションに対して一度だけ使用します。

_confirmation.htmlで:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<div id="buttons" class="flex flex-wrap justify-center gap-10">
    <button hx-target="#contact-form" hx-swap="innerHTML"
            hx-post="send/"
            _="on click toggle .hidden on #indicator then remove #buttons"
            class="max-w-fit px-14 py-4 bg-cyan-600 text-slate-100 text-2xl transition ease-in-out duration-300 hover:bg-cyan-600 cursor-pointer">
        Send
    </button>
    ...
</div>

<div id="indicator" class="hidden mx-auto">
    <svg id="L4" class="fill-cyan-500 mx-auto"
         ...
    </svg>
</div>

ユーザーがSendボタンをクリックすると、_hyperscriptはSVGアニメーションのdivである#indicator要素のhiddenというTailwindCSSユーティリティクラスをトグルし、その後#buttons要素を削除します。

_hyperscriptは小型のライブラリであるため、本様のように少量しか使わなくてもパフォーマンスに大きな影響を及ぼすことはありません。 コンタクトフォームではそれほど使用していませんが、HDA開発者がすべての振る舞いをHTMLにローカリゼすることを可能にするため、GRUG Stackの重要なメンバーであると言えます。

結論

あなたがフルスタック開発者であり、生活を煩雑化せずに最新のアプリケーションを開発するために必要な機能を提供するテクノロジースタックを探しているなら、GRUG Stackはあなたに向いています。

あなたがGRUG Stackを立ち上げて実行する方法についてのガイドが必要なら、当サイトのガイド が参考になるかもしれません。

Profile Photo

Author

Added

2023年11月29日

Technologies
HTMX HTMX
TailwindCSS TailwindCSS
Django Django