Laravel 10+Inertia.js+Tailwindインストール Inertia入門#2

Laravel

この記事ではLaravelにInertia.jsをインストールしてHello Worldを出力する方法までを解説します。

Laraveler
Laraveler

前の記事でInertiaについては大体わかりましたので、どうやって使うか教えてください!

シップ
シップ

では今回はLaravelにInertia.jsを導入して簡単なサンプルを作成してみましょう!

前回の記事ではInertia.jsについて、どういうものか概要を解説しました。そちらも合わせてお読みください。

バージョン情報
  • Laravel 10 (執筆時のバージョンは10.18)
  • Vue3
  • TailwindCSS
  • Vite
npm list --depth=0
+-- @inertiajs/vue3@1.0.10
+-- @vitejs/plugin-vue@4.2.3
+-- autoprefixer@10.4.14
+-- axios@1.4.0
+-- laravel-vite-plugin@0.7.8
+-- postcss@8.4.27
+-- tailwindcss@3.3.3
`-- vite@4.4.9
composer show -i
inertiajs/inertia-laravel          v0.6.9   The Laravel adapter for Inertia.js.
laravel/framework                  v10.18.0 The Laravel Framework.

Laravelのインストール

この記事では、Laravel10を用いて解説を進めていきます。Laravelの環境構築についてはこちらの記事も参考にするとDockerを使用して楽にLaravelの開発環境を構築できます。このシリーズ記事では下記のリポジトリからDockerでのLaravel環境をクローンして行っていきます。

Dockerのインストールは事前に済んでいるものとします。

DockerでLaravel開発環境をクローン

cd /home/ship/project/
git clone https://github.com/shipwebdotjp/docker-laravel.git inertiademo-laravel10
cd inertiademo-laravel10/

まず、お好きな場所で構いませんが、プロジェクトを作成したいディレクトリに移動します。その後、リポジトリからDockerのLaravel環境のテンプレートをダウンロードして、そのプロジェクトディレクトリに移動します。

make create-project

Dockerコンテナの作成とLaravelのインストールを行います。

以降のコマンドはLaravelをインストールしたディレクトリで実行します。上記のDockerでLaravel環境を構築した場合は、「make app」または「docker-compose exec app bash」を実行してLaravelのコンテナに入ってから実行して下さい。

make app
docker-compose exec app bash
root@861c134e5ba8:/work/backend# (Laravelコンテナの中)

サーバーサイドの設定

Inertia.jsはサーバーサイドとクライアントサイド両方に関わってきます。まずはサーバーサイドの設定をしていきます。スターターキットと呼ばれる、認証システムなどがセットになったパッケージをインストールすると自動的にInertiaの環境が揃います。ただ、今回は最小限の構成にしたいのと、理解を深めるためにスターターキットを使用せずInertiaを使える状態にしていきます。

手動でInertia.jsをインストール

composer require inertiajs/inertia-laravel

composerを利用してInertiaの依存パッケージをインストールします。

Using version ^0.6.9 for inertiajs/inertia-laravel
./composer.json has been updated
Running composer update inertiajs/inertia-laravel
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking inertiajs/inertia-laravel (v0.6.9)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Downloading inertiajs/inertia-laravel (v0.6.9)
  - Installing inertiajs/inertia-laravel (v0.6.9): Extracting archive
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   INFO  Discovering packages.

  inertiajs/inertia-laravel ....................................................................................... DONE
  laravel/sail .................................................................................................... DONE
  laravel/sanctum ................................................................................................. DONE
  laravel/tinker .................................................................................................. DONE
  nesbot/carbon ................................................................................................... DONE
  nunomaduro/collision ............................................................................................ DONE
  nunomaduro/termwind ............................................................................................. DONE
  spatie/laravel-ignition ......................................................................................... DONE

83 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force

   INFO  No publishable resources for tag [laravel-assets].

ルートテンプレートの編集

resources/views/ディレクトリにapp.blade.phpというファイルを以下の内容で作成します。これがInertiaでアクセスした際のデフォルトのテンプレートになります。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    @vite('resources/js/app.js')
    @inertiaHead
  </head>
  <body>
    @inertia
  </body>
</html>

ミドルウェアの作成

Inertiaリクエストを処理するためのミドルウェアの作成を次のartisanコマンドで行います。

php artisan inertia:middleware
   INFO  Middleware [app/Http/Middleware/HandleInertiaRequests.php] created successfully.

ミドルウェアの登録

app/Http/Kernel.phpを開き、$middlewareGroupsのwebへ、いま作成したHandleInertiaRequestsミドルウェアを登録します。

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            \App\Http\Middleware\HandleInertiaRequests::class,//←追加
        ],

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

スターターキットを使用する方法

jetstreamなどを利用するとInertia+Vue+TailwindCSSの環境が一発で整いますが、今回はjetstreamの認証は必要ないため、jetstreamなどのスターターキットを使う方法は詳しく解説は行いません。

ルーティングとレスポンスを作成

では実際にInertiaを使った表示を行うため、ルーティングを管理している「routes/web.php」を編集し、コントローラーを作成せずに直接ビューを返すルーティングを追加してみましょう。

「/HelloWorld」にアクセスがあった時、「HelloWorld」ビューを返すInertiaレスポンスは次のように書きます。これを「routes/web.php」の末尾に追記します。

use Inertia\Inertia;

Route::get('/HelloWorld', function () {
    return Inertia::render('HelloWorld');
});

サーバー側の設定は以上です。次に、フロント側の設定に移ります。

フロントエンド側の設定

nodeを使用してインストールを行うため、一旦appコンテナから出て、webコンテナに入ります。

exit
make web

その後、フロントエンドで使う技術に合わせたパッケージをインストールします。

手動での依存パッケージのインストール

今度はクライアントサイドで使用する、Vue.jsのコンポーネントを作成していきます。

Inertia.jsはVue2,Vue3,React,Svelteで使用できますが、このシリーズ記事ではVue3を用います。

まずVue3をViteで扱えるようにします。ViteのVueプラグインをインストールします。

npm install @vitejs/plugin-vue --save-dev

vite.config.jsを修正して、Vueファイルを処理できるようにします。

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from "@vitejs/plugin-vue"; //←追加

export default defineConfig({
    plugins: [
        vue(), //←追加
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
});

Inertia.jsをVue3で使用するためのライブラリをインストールします。

npm install @inertiajs/vue3

Inertiaアプリの初期化

メインのJavaScriptファイルとなるresources/js/app.jsでInertiaアプリの初期化を行います。

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
  resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
    return pages[`./Pages/${name}.vue`]
  },
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

Vue.jsのPageコンポーネントを作成

resources/js/配下にPagesディレクトリを作成し、そこにVue.JSのコンポーネントを作成します。

「HelloWorld.vue」というファイル名でHello Worldと表示するだけのコンポーネントファイルを作成します。

<template>
    <div>
        Hello world!
    </div>
</template>

保存したらWebコンテナで下記を実行します。これでpackage.jsonのscriptのdevで定義されているコマンドが実行されます。

npm run dev

Laravel10ではフロントエンドのバンドルツールとして旧来のwebpackではなく、Viteが採用されているため、Viteが起動します。

/work/backend # npm run dev

> dev
> vite


  VITE v4.4.9  ready in 409 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

  LARAVEL v10.18.0  plugin v0.7.8

  ➜  APP_URL: http://localhost

アセットファイルの更新を検知して自動的にコンパイル+ホットリロードしてくれます。

Dockerで実行している場合、Viteのサーバーにホストからアクセスできるようvite.config.jsに設定を加える必要があります。

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from "@vitejs/plugin-vue";

export default defineConfig({
    plugins: [
        vue(),
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
    //この下の部分を追加
    server: {
        host: true,
        hmr: {
            host: 'localhost',
        },
    },
});

http://localhost/HelloWorld」にアクセスして「HelloWorld」と表示されていれば成功です。

TailwindCSSのインストール

見た目を整えるため、このシリーズではTailwindCSSを使用します。見た目はどうでもいいという方はこのステップは飛ばしていただいても構いません。

npm install -D tailwindcss postcss autoprefixer
added 83 packages, and audited 136 packages in 11s

28 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

上記のnpm installコマンドでtailwindcss、postcss、autoprefixerをインストールします。

npx tailwindcss init
/work/backend # npx tailwindcss init

Created Tailwind CSS config file: tailwind.config.js

tailwindcssの初期化コマンドでtailwind.config.jsが作成されるので、content配列部分に、どの種類のファイルのTailwindCSSクラスを処理するかを指定します。ここではblade、js,vueファイルを指定します。

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./resources/**/*.blade.php",
    "./resources/**/*.js",
    "./resources/**/*.vue",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

次にpostcssの設定ファイルpostcss.config.cjsを新規作成します。(拡張子が.jsではなく、.cjsなことに注意してください)

module.exports = {
    plugins: {
        tailwindcss: {},
        autoprefixer: {},
    },
}

CSSのJavaScript埋め込みを用いるので、vite.config.jsのlaravelのエントリーポイントからcssは削除します。

        laravel({
            input: ['resources/js/app.js'], //←'resources/css/app.css'を削除
            refresh: true,
        }),

代わりにJavaScriptのエントリーポイントでCSSもimportするようにします。

import '../css/app.css';
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
  resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
    return pages[`./Pages/${name}.vue`]
  },
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

CSSエントリーポイントのresources/css/app.cssにデフォルトのtailwindCSSの各クラス設定を読み込むよう設定します。

@tailwind base;
@tailwind components;
@tailwind utilities;

Linkの動作確認

Inertia.jsでは、<Link>というコンポーネントを使用してリンクを作成すると、クリックした際にXHRでのリクエストがされるようになります。この動作を確認してみます。

「HelloWorld.vue」にホームへ戻る<Link>を追加します。

Inertiaのコンポーネントを利用する際には、明示的にimportする必要があります。

<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
    <div>
        Hello world!
        <Link href="/" class="text-sm text-blue-700 underline">
                ホームへ戻る
        </Link>
    </div>
</template>

http://localhost/HelloWorld」にアクセスすると「HelloWorld ホームへ戻る」と表示されます。

ブラウザの開発者ツールでネットワークを見てみると、HTMLが返ってきていることが分かります。このように初回のアクセスはフルHTMLが返ります。

インスペクタでDOMツリーをみると、リンクは普通にaタグで作成されていることが分かります。ただし、クリックイベントを補足するイベントリスナーが登録されており、クリック時に通常のリクエストを送るのではなく、XHRリクエストを送信するメソッドが呼び出されているということが推察できます。

<a class="text-sm text-blue-700 underline" href="http://localhost/"> ホームへ戻る </a>

次に「ホームへ戻る」のリンクをクリックするときのリクエストを見てみます。

X-Inertia: true
X-Requested-With: XMLHttpRequest

「X-Inertia」ヘッダーが付加されてXMLHttpRequest(XHR)で送信されていることが分かります。

レスポンスは、今アクセスしたのはInertia化していないトップページのためtext/htmlが返ってきて、モーダルで表示されます。

リンク先をInertiaで動かしているページに変更すると、動作が変化します。

試しに自分自身のページを呼び出すようにHelloWorld.vueを変更してからリンクをクリックしてみます。

        <Link href="/HelloWorld" class="text-sm text-blue-700 underline">
                HelloWorld
        </Link>
Content-Type: application/json

この場合、JSONオブジェクトが返ってきます。それでも画面上はHello Worldが表示されています。このようにInertia.jsが、クライアントサイドではリンクをXHRに変えてリクエストを送り、サーバーサイドではX-Inertiaヘッダーの有無をチェックしてフルHTMLを返すかJSONデータのみを返すかを決定していることが分かります。

今回の内容
  • LaravelにInertia.jsの動作環境を作成
  • 簡単なVueコンポーネントを作成し、Inertia.jsでルーティング
  • Linkを使用して、XHRリクエストになるリンクを作成

ソースコード

今回のソースコードはGitHubで公開しています。

次回は、コントローラーからInertiaレスポンスを返す方法と、Inertiaでルーティングをする方法を取り上げます。

Inertia.js入門記事一覧
Inertia.jsでシンプルにSPAを構築する Inertia入門#1
Inertia.jsを使うとLaravelやRubyonRailsなどのフレームワーク上でAjax用のAPIやコントローラーを作成しなくても、通常のビューを使う要領でSPA(シングルページアプリケーション)が構築できます。
Laravel 10+Inertia.js+Tailwindインストール Inertia入門#2
この記事ではLaravelにInertia.jsをインストールしてHelloWorldを出力する方法までを解説します。
Inertia.jsのルーティングとレスポンス作成 Inertia入門#3
Laravel8でjetstreamを入れるとLimewireかInertiaかを選べます。この記事ではInertiaを使ってルーティングやInertiaレスポンスの返し方を解説します。
Inertia.jsでページレイアウト Inertia入門#4
この記事では、ページレイアウトについて解説します。親レイアウトに子ページを組み込むことで、ヘッダーやフッターを共通化できます。
Inertia Linkの使い方 Inertia.js入門 #5
この記事では、Inertia.jsのLinkコンポーネントについて解説します。
Inertia.jsでXHRリクエスト Inertia.js入門 #6
この記事では、Inertia.jsで非同期通信を行うrouter.visit()について解説します。
Inertia.jsでのフォームとリダイレクト Inertia.js入門 #7
この記事では、Inertia.jsでのフォーム送信とリダイレクトについて解説します。
Inertiaでのバリデーション Inertia.js入門 #8
この記事では、Inertia.jsを使った際のバリデーションエラーの表示について解説します。
Inertiaで共通データとフラッシュメッセージ Inertia.js入門 #9
この記事では、Inertiaのレスポンスに毎回同じデータを含める方法やフラッシュメッセージの使い方について解説します。
この記事を書いた人

PHPが好物な個人開発プログラマ。フリーランスエンジニアとしてWebサービス作ったりしてます。15年の経験を生かしてMENTAでメンターもやってます。WordPressやPHPでお困りのことがあればご相談に乗りますのでDMください。

Follow on SNS
Laravel
SOHO MIND

Comments

タイトルとURLをコピーしました