PHPerでも「htmx」を使いたい!Laravelでhtmxを行う方法

こんにちは、いつものたーなつです。
今回はExciteTechブログの中では二番煎じな「htmx」というものをやってみたいと思います。

先駆者のブログは以下です。
tech.excite.co.jp

htmxとは?

Ajax系のJavaScriptをほぼ書かずに、SPAを実現するための技術になります。
フロントエンドのJavaScript系のコードを削減 & Reactなどのフレームワークを極力不要にしていけそうな技術になります。

htmxの公式は以下です。 htmx.org

Laravelのインストール

はい、私はPHP × Laravelが(今の所)大好きですので、
Laravelを利用します。

$ composer create-project laravel/laravel プロジェクト名

なお、記事作成時点での環境は以下になります。

  • PHP 8.2
  • Laravel 9.50.2
  • Laravel Livewire 2.11.2

Laravel Livewireのインストール

「Laravel Livewire」はLaravelでhtmxを利用できるようにするライブラリです。

laravel-livewire.com

導入コマンドは以下です。

$ composer require livewire/livewire

これで設定完了です。

サクッとLivewireしてみる

基盤のHTMLを作成

まずは最初のアクセスを行ったときに表示されるページを作成します。
index.blade.phpとして、resource/view配下に置きます。

<html>
<head>
    <title>htmx</title>

    @livewireStyles
</head>
<body>
こんにちは世界!

@livewireScripts
</body>
</html>

@livewireStyles@livewireScriptsがミソですね。
これらを書くことで、SPAに必要なJavaScriptなどを自動で出力してくれます。

基盤のweb.phpも変更しましょうか。

// 略

Route::get('/', function () {
    return view('index');       // ←welcomeから変更した
});

これで基盤の準備は完了です。

controllerとviewを準備する

ひとまずドキュメントに沿ってやっていきます。

$ php artisan make:livewire 作成したいコンポーネント名

このコマンドで必要なファイルを自動で吐き出してくれます。
app/Http/Livewire/配下にcontrollerが出力され、
resources/views/livewire配下にviewが出力されます。

今回は先駆者を真似て、フォームの入力をそのままHTMLに反映させるコードを書いてみます。

以下のコマンドを実行して、controllerとviewを作成します。

$ php artisan make:livewire DisplayForm

追加したDisplayFormを表示する

index.blade.phpを次のように書き換えます。

<html>
<head>
    <title>htmx</title>

    @livewireStyles
</head>
<body>
こんにちは世界!
<livewire:display-form>

@livewireScripts
</body>
</html>

<livewire:display-form>を追加しました。

追加したDisplayFormの動作を定義する

追加されたapp/Http/Livewire/DisplayForm.phpを以下のように書き換えます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class DisplayForm extends Component
{
    public string $formText;   // ←追加

    public function render()
    {
        return view('livewire.display-form');
    }
}

追加されたDisplayFormの表示を定義する

追加されたresources/views/livewire/display-form.blade.phpを以下のように書き換えます。

<div>
    <input type="text" wire:model="formText"><br>

    入力テキスト:{{ $formText }}
</div>

wire:model="formText"で、
controllerで定義したpublic string $formText;と値がバインドされます。

これで終わりです!

動作画面

ちょっとだけアレンジ

さて、htmxの何が良いかというと、
viewは「表示だけを考えればいい」ということです。

つまり、表示以外のロジックをサーバサイド、今回であればPHPに閉じ込めることができるんですね。
viewでifとかfunctionとかそういうのを減らすことができるわけです。

というわけで、ロジックを少し追加してみます。

app/Http/Livewire/DisplayForm.phpを以下のように書き換えます。

<?php

namespace App\Http\Livewire;

use Livewire\Component;

class DisplayForm extends Component
{
    public string $formText = '';    // ←初期化しておかないとエラーになる

    public string $coloredText = '';   // ←出力用の変数($formTextをPHPで書き換えると、viewにも反映されてしまうので変数を分ける)

    public function render()
    {
        $this->generateText();

        return view('livewire.display-form');
    }

    private function generateText()
    {
        // テキストを1文字ずつの配列に分解
        $textList = mb_str_split($this->formText);

        $coloredTextList = array_map(function (string $char) {
            // ランダムなカラーコード作成
            $colorCode = sprintf('#%06x', rand(0x000000, 0xFFFFFF));

            // 1文字ずつにランダムに色を付ける(本当はbladeとかで処理するべきだけど、簡単のため省略)
            return sprintf('<span style="color: %s">%s</span>', $colorCode, $char);
        }, $textList);

        $this->coloredText = implode('', $coloredTextList);
    }
}

次にresources/views/livewire/display-form.blade.phpを以下のように書き換えます。

<div>
    <input type="text" wire:model="formText"><br>

    入力テキスト:{!! $coloredText !!}
</div>

出力サンプル

以上です!


というわけで、今回はhtmxというものをPHPでやってみました。
可能な限りフロントからロジックを消し、処理をカプセル化できるといいですねー

というわけで、htmxの紹介でした!
ではまた、次回!