htmxをSpringBoot Thymeleafで試してみる(1)

エキサイト株式会社メディア事業部エンジニアの佐々木です。htmxは、React.jsやVue.jsなどの大きいフロントエンドフレームワークを用いることなく、SPAのような仕組みを提供してくれるライブラリになります。

htmx.org

htmxとSpringBoot Thymeleafを使用して、簡単なサンプルを作ってみます。

動作確認環境

動作確認環境としては下記になります。

Java

$ java --version
openjdk 17.0.1 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12-39)
OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)

Spring

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.1)

どの環境でも動くと思います。

Gradle

$ ./gradlew --version

------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------

Build time:   2022-11-25 13:35:10 UTC
Revision:     daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8

Kotlin:       1.7.10
Groovy:       3.0.13
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          17.0.1 (Oracle Corporation 17.0.1+12-39)
OS:           Mac OS X 12.5 aarch64

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    compileOnly 'org.projectlombok:lombok'

    implementation 'org.webjars.npm:htmx.org:1.8.5'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
}

HTMX

htmx.org/1.8.5

SpringBoot側のコード

Lombokは使用していますが、通常のSpringBootのコードになります。

@Controller
@RequestMapping("/")
public class RootController {

    @GetMapping("") // Getリクエストを受け付ける用の設定
    public String index(Model model) {
        return "index";  // index.htmlを返却します
    }

    @PostMapping("/upper").  // Postリクエストを受け付ける用の設定
    public String upper(Model model, Form form) {
        model.addAttribute("response", form);
        return "upper";  // upper.html を返却します
    }

    @Data
    static class Form {
        private String query;
        public String getUpperCase() { // 大文字にして返却するメソッド
            return this.query.toUpperCase();
        }
    }
}

HTML

index.html は下記のようなファイルになります。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/webjars/htmx.org/1.8.5/dist/htmx.min.js"></script> // htmxのJSのライブラリ14.2KB
</head>
<body>

<div>
<input 
    type="text"
    name="query"
    hx-post="/upper"  // PostリクエストするURL
    hx-trigger="keyup changed delay:100ms"   // 動作条件を設定( 100ms遅れでkeyup 且つ 変更の場合)
    hx-target="#result"   // id="result"を更新対象にする
/>
    <div id="result">

    </div>
</div>
</body>
</html>

htmxのJSがhx-xxxxので設定されているものを検知して動作してくれます。JSを1行も記述していません。

続いて、upper.html になります。

<span style="font-size: 24px; font-weight: bold">
    [[${response.getUpperCase()}]]
</span>

これは、hx-postでリクエストされたものを返却する用のテンプレートファイルになります。中で下記のJavaオブジェクトのgetUpperCaseメソッドをテンプレートファイルから呼び出しています。

    @Data
    static class Response {
        private String query;

        public String getUpperCase() {
            return this.query.toUpperCase();
        }
    }

こうすることで、バックエンドはデータ処理に、フロントエンドは表示処理に専念できます。

実行

SpringBootを起動して、試してみましょう。 入力フォームにhello world と入力してみます。

やってみると、入力の度に、/upperにリクエストしているのがわかります。

まとめ

今回のパターンでは、1行もJSを記述していません。そして、この例はhtmxができることのほんの一例にすぎません。他にもServer Sent EventWebSocketとの連携、PushStateなどの機能が簡単に使えるようになっており、MPAアプリケーションなのにSPAの挙動を容易に実現できそうです。海外ではReact.jsからhtmxに置き換えて、結構なパフォーマンス改善ができたようです。

A Real World React -> htmx Port

弊社でのユースケースがあえば、導入も行ってみたいと思います。

最後に

エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。

カジュアル面談はこちらになります! meety.net

募集職種一覧はこちらになります!(カジュアルからもOK) www.wantedly.com