👋

Laravelモダンフロントエンド開発ガイド:Breeze、Vite、Livewire、Inertia.js

2024/09/22に公開

概要

Laravelアプリケーションでのフロントエンド開発にはいくつかの選択肢があります。大きくはLaravel標準に沿う方法と、Laravelをバックエンドとしてのみ使う方法の2つです。

Laravel標準のフロントエンドスタックとしては、JetstreamやBreezeを使って認証機能を簡単に導入することができ、Inertia.jsやLivewireを使ってSPAを構築することも可能です。JSフレームワークを使わない場合でも、Laravel Viteを使って独自にフロントエンドをビルド環境を構築することができます。

バックエンドとしてのみLaravelを使う場合は、公式リポジトリではNext.jsを使ったサンプルがあります。Next.jsやRemixを使って静的なSPAを構築して分離するという方法もあります。

CSSフレームワークとしてはBootstrapからTailwind CSSへの移行が進んでいます。

ユーティリティライブラリとしてはlodashが削除されましたが、axiosはデフォルトでインストールされています。

ビルドツール

Laravel Mix

Laravel Mixは、Webpackをラップしたツールです。JavaScript、CSS、Sass、Less、Stylusなどのアセットをバンドルおよび変換する機能を提供します。

Mixを使うと、Laravelプロジェクト用のWebpackのプラグイン設定を動的に構築するので、Webpackを細部まで理解する必要がありません。

反面、Mixを通してWebpackの設定ファイルを書くので、柔軟性に欠けます。

新規導入はせず基本的に後述のLaravel Viteに置き換えるとよいでしょう。

Laravel Vite

Laravel 9では、フロントエンドビルドツールとしてViteが標準で採用されています。Laravelプロジェクトを作成すると、Viteに関連する設定ファイルが自動的に含まれるようになりました。

ViteはWebpackを代替するモダンなフロントエンド開発ツールで、高速なビルドやホットリロードなどの機能を提供します。

Mixと同じように公式プラグインとBladeディレクティブを使う方式なので、MixからViteに移行するのは比較的容易です。

認証システム

Laravel Sanctum

Laravel Sanctumは、Laravelプロジェクトにシンプルな認証システムを提供するパッケージです。Laravel Passportの一部のユースケースを置き換えるものです。

Laravel Fortify

Laravel Fortifyは、Laravel用のフロントエンド非依存の認証バックエンド実装です。Fortifyは、ログイン、登録、パスワードリセット、メール確認などのLaravelのすべての認証機能を実装するために必要なルートとコントローラーを登録します。

Fortifyは認証機能全般を包括的に扱うのに対し、SanctumはAPIトークン管理とセッション認証に特化しています。組み合わせて使えるもので、競合するパッケージではありません。

JavaScriptフレームワーク

VueとReact

一昔前まではLaravelといえばVue.jsというイメージがありました。これはLaravel標準のJavaScriptライブラリとしてVue.jsが採用されていたためです。

近年はReactのユーザー規模が拡大したため、どちらかがデフォルトという状況ではなくなりました。ユーザーは必要に応じてライブラリを導入して使うことになります。

Next.js

公式リポジトリにはNext.jsとLaravelとの連携サンプルがあります。ただし、このサンプルはTypeScriptではありません。

https://github.com/laravel/breeze-next

Next.jsを使う場合、ビルドは完全にLaravelの外で行うので、Laravel Viteとは連携しません。それぞれのリポジトリ(もしくはモノレポの場合はディレクトリ)でビルド作業して、Laravelサーバーと連携することになります。

サンプルではJSから/sanctum/csrf-cookieのエンドポイントを叩きcookieを取得して、認証Hookを作っています。

フルスタックフレームワーク

Next.jsなど外部のフレームワークを使わない場合は、Laravelが推奨するフロントエンドの構築方法はLivewireとInertia.jsの2つ系統があります。

それぞれ明確に設計が異なり、LivewireはLaravelとの親和性が高く、Inertia.jsはJSライブラリとの親和性が高いです。

Livewire

Livewireは、LaravelのBladeテンプレートとPHPで動的でリアクティブなUIを構築するためのライブラリです。

Bladeテンプレートをベースにしているので、Laravel独自のライブラリです。

LivewireはLaravelのコントローラーとビューを活用して、PHPでフロントエンドのコンポーネントを作っていくことができます。

セッション状態やDB参照結果などをサーバーサイドで取得できるので、クライアントサイドとの連携が減りシンプルになります。

インストールとセットアップ

Livewireをインストールするには、Composerを使って以下のコマンドを実行します。

composer require livewire/livewire

次に、BladeテンプレートでLivewireを使用するために、@livewireStyles@livewireScriptsディレクティブを追加します。

<!DOCTYPE html>
<html>
<head>
    <title>Livewire Example</title>
    @livewireStyles
</head>
<body>
    @livewire('counter')

    @livewireScripts
</body>
</html>

基本的な使用例

以下は、カウンターコンポーネントの例です。

// app/Http/Livewire/Counter.php
namespace App\Http\Livewire;

use Livewire\Component;

class Counter extends Component
{
    public $count = 0;

    public function increment()
    {
        $this->count++;
    }

    public function render()
    {
        return view('livewire.counter');
    }
}
<!-- resources/views/livewire/counter.blade.php -->
<div>
    <button wire:click="increment">+</button>
    <h1>{{ $this->count }}</h1>
</div>

このように、Livewireを使うことで、PHPとBladeテンプレートだけで動的なUIを簡単に構築することができます。

Inertia.js

Inertia.jsは、サーバーサイドレンダリングの利点を維持しながら、モダンなシングルページアプリケーション(SPA)のフロントエンドを構築することを可能にするフレームワークです。

Laravel独自のフレームワークではなく、Railsなどにも対応しています。

利用するには、Laravelのinertia-laravelパッケージをインストールして、さらにJSのInertia.jsパッケージをクライアントサイド用にインストールする必要があります。

composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-vue3

基本的な使用例

以下は、Inertia.jsを使った基本的な使用例です。

// routes/web.php
use Inertia\Inertia;

Route::get('/', function () {
    return Inertia::render('Home', [
        'foo' => 'bar',
    ]);
});
// resources/js/app.js
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'

createInertiaApp({
  resolve: name => require(`./Pages/${name}`),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})
<!-- resources/js/Pages/Home.vue -->
<template>
  <div>
    <h1>Welcome</h1>
    <p>{{ foo }}</p>
  </div>
</template>

<script>
export default {
  props: {
    foo: String,
  },
}
</script>

Inertia.jsでは、サーバーサイドフレームワークから、JavaScriptのページコンポーネント名とデータ(props)を含むJSONを内部的に受け取ります。

こうするとJSで書いたコンポーネント用にAPIを個別で作る必要がなくなり、従来のサーバーサイドのMVCのように、フロントエンドのコンポーネントを作っていくことができます。

ページ遷移は専用の<Link>コンポーネントを使って行い、Inertia.jsが自動でサーバーと連携してページデータや状態変数を受け取り、クライアントサイドで画面遷移を行います。

ただサーバーサイドから返されるのは完全なHTMLページではないので、JavaScriptを実行ないと描画できません。JavaScriptが実行されないクローラーなどが解釈できなく、検索エンジン最適化(SEO)に弱いという欠点があります。

そして描画されたHTMLから動的なSPAを再生することになると、埋め込まれた値をJSで利用可能にするためのハイドレーションが必要になります。それには追加の対応が必要になります。なのでSSR要件によってInertia.jsの導入難易度は変わります。

Laravel JetstreamとLaravel Breeze

Laravel Jetstreamは、Laravelプロジェクトの認証機能やダッシュボード機能を提供するスターターキットのパッケージです。

ログイン、登録、メール確認、2要素認証、セッション管理、Laravel Sanctumを使用したAPIサポート、そしてオプションのチーム管理など、アプリケーションに必要な基本的な機能を提供します。

Laravel Breezeはさらに機能を最小限にして、必要なライブラリを個別設定できるようにしたパッケージです。

これらはTailwind CSSを使用しており、それにくわえて開発者はLivewireまたはInertiaのいずれかのフロントエンドスタックを選択します。

JetstreamとBreezeの関係は、JetstreamをよりシンプルにしたものがBreezeという位置づけになります。Laravel Breezeを先に試してみて、その後Jetstreamだけの機能が欲しければJetstreamを導入するという順番になります。

個人的にはJetstreamはあまりコミュニティ受け入れられていないので、Breeze+個別設定の方に収束していくと思います。

どれも使わない:SPA (React/Vueなど)

JSフレームワークもこれらのlivewireもinertia.jsも使わない場合は、Laravel Viteでビルドしたフロントエンドのコードをベースに必要なコンポーネントでページを作っていくことになります。

これは一般的なSPAの開発と同じです。好きなクライアントサイドのルーティングライブラリを使ってもいいですし、起点となるURLを複数持つMPAとして開発してもいいです。

しかしJSコンポーネントのSSRが必要ならNode.jsを実行するサーバーを用意する必要があります。

next export or Remix SPA mode

Next.jsはビルド済みのコードを静的なSPAとして出力する機能があります。

RemixにもSSRを伴わない性的なSPAを作るモードがあります。ルーターにはreact-routergが組み込まれています。

これらは実質的にはLaravel Viteでビルドしたフロントエンドと解決方法は同じです。

SPAを構築して、それをPHPのウェブサーバーより前段か、もしくはLaravelのpublicディレクトリに配置することで、フロントエンドとしてホストします。

もしSSRを導入したくなったらNode.jsを実行するサーバーでフロントエンドを置き換えることになります。

Bladeのみ

そもそも動的なUIやリアルタイムのインタラクションが不要な場合は、従来のLaravelのBladeのviewのみで開発することも可能です。管理画面などのバックオフィスの運用では今でもよくみられる選択です。

CSSフレームワーク

Tailwind CSS

LaravelではBootstrapがよく使われていましたが、近年はTailwind CSSが主流になっています。

デフォルトではなく、Laravel Breeze経由で導入するか、自ら追加導入するかの2択になります(ただwelcome.bladeテンプレートにインラインで埋め込まれてはいます)。

ユーティリティライブラリ

lodash

Laravel 10ではlodashが依存から削除されました。9までは標準でlodashが含まれていました。

本体ではなく関連パッケージでlodashの関数がつかわれていたようです。

現在はlodashの機能はほとんどがネイティブのJSで解決できるので、導入する必要がなくなりました。

axios

一方でaxiosはデフォルトでインストールされています。laravel/echoなどの複数の関連パッケージでX-CSRF-TOKENつきHTTPクライアントとして使われています。

laravel利用者的には削除しても問題ありませんが、関連パッケージで使われているので、それら導入すると必要になります。

各フロントエンド開発方法のトレードオフ

最後にこれらの選択肢の持つトレードオフをまとめてみました。

方法 メリット デメリット
Bladeのみ - シンプルな構造: PHPとBladeテンプレートだけで開発でき、追加のJavaScriptフレームワークが不要。
- 学習コストが低い: PHPやBladeに習熟していれば、新たな技術を学ぶ必要がない。
- サーバーサイドレンダリングによるSEO最適化: 完全にサーバーサイドでレンダリングされるため、SEOに強い。
- 動的なUIの制限: クライアントサイドでのインタラクションが限定的で、複雑なUIを構築するのが難しい。
- ページ遷移の遅延: ページごとに全体を再レンダリングするため、SPAに比べてユーザー体験が劣る。
Next/Remix/Nuxtなどのフレームワーク - 高度なフロントエンド機能: モダンなJavaScriptフレームワークの機能を活用できる。
- サーバーサイドレンダリング(SSR): 高速な初回表示とSEO対策が可能。
- 豊富なエコシステム: プラグインやライブラリが豊富で、拡張性が高い。
- 複雑な設定: 統合や設定が複雑で、Laravelとの連携に工数がかかる場合がある。
- 学習コスト: 新たなフレームワークを習得する必要があり、開発者のスキル要件が上がる。
- ビルドプロセスの管理: フロントエンドとバックエンドのビルドプロセスを別々に管理する必要がある。
SPA (React/Vueなど) - リッチなユーザーインターフェース: 高度なインタラクティブ性とシームレスなユーザー体験が実現可能。
- コンポーネントベース: 再利用可能なコンポーネントで開発効率が向上。
- フロントエンドの独立性: バックエンドとフロントエンドを独立して開発・デプロイできる。
- SEOの課題: クライアントサイドレンダリングの場合、SEO対策が難しくなることがある。
- 初期ロード時間: 完全なSPAでは初回ロードが重くなる傾向がある。
- 複雑な状態管理: アプリケーションの規模が大きくなると、状態管理が複雑になる可能性がある。
Livewire - シームレスな統合: LaravelのBladeとPHPで動的なUIを構築でき、フロントエンドとバックエンドの統合が容易。
- リアクティブなインターフェース: クライアントサイドでのJavaScriptを最小限に抑えつつ、動的なUIを実現。
- 学習コストが低い: PHPに慣れている開発者にとって導入が容易。
- パフォーマンスの制約: 多数のリクエストが発生する場合、サーバーへの負荷が増加する可能性がある。
- フロントエンドの柔軟性: 完全なSPAに比べて、フロントエンドのカスタマイズ性が制限される。
- JavaScriptとの連携: JavaScriptとの連携が必要な場合、追加の実装が必要になることがある。
Inertia.js - サーバーサイドとフロントエンドのシームレスな統合: LaravelとモダンなJavaScriptフレームワーク(Vue、React、Svelteなど)を相互に連携可能。
- SPAのようなユーザー体験: ページ遷移がスムーズで、ユーザー体験が向上。
- 既存のLaravelアプリケーションへの導入: 既存のLaravelプロジェクトに容易に統合できる。
- フロントエンドフレームワークの必要性: VueやReactなど、JavaScriptフレームワークの知識が求められる。
- 学習コスト: Inertia.js特有の概念や機能を学ぶ必要がある。
- SSRが難しい: サーバーサイドレンダリングは拡張機能のため、別途対応が必要。

これらの選択肢から最適なフロントエンド開発方法を選ぶ際は、プロジェクトの要件やチームのスキルセット、将来的な拡張性などを総合的に考慮してください。

参考文献

https://laravel.com/docs/11.x/starter-kits

Discussion