Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Laravel x Inertia.js 現代のモノリス によるお手軽 SPA 開発

tutida
June 24, 2023

Laravel x Inertia.js 現代のモノリス によるお手軽 SPA 開発

tutida

June 24, 2023
Tweet

More Decks by tutida

Other Decks in Programming

Transcript

  1. 自己紹介 内田 大順 Uchida Tomoyuki - ID - GitHub:tutida -

    Twitter:@_tutida_ - Work at - 株式会社 Fusic (フュージック) - プリンシパルエンジニア - Skill - 本日の資料 - https://speakerdeck.com/tutida/ - 最近のこと - 今日(6/24)が奥さんの誕生日と気づかずプロポーザルを申 し込んでいた 2
  2. Laravel での SPA • バックエンド / フロントエンドが疎結合 • APIスキーマによる型制約やモック •

    それぞれの開発に集中できる API APIサーバ フロントの何か LaravelをAPIサーバとして利用すると 良い点 8
  3. Laravel での SPA • バックエンド / フロントエンドが疎結合 • APIスキーマによる型制約やモック •

    それぞれの開発に集中できる API APIサーバ フロントの何か LaravelをAPIサーバとして利用すると 良い点 • APIスキーマ・リポジトリの管理 • 開発スピードの初速が出にくい • お互いの開発に無関心になりやすい 要検討 9
  4. Laravel での SPA • バックエンド / フロントエンドが疎結合 • APIスキーマによる型制約やモック •

    それぞれの開発に集中できる API APIサーバ フロントの何か LaravelをAPIサーバとして利用すると 良い点 • APIスキーマ・リポジトリの管理 • 開発スピードの初速が出にくい • お互いの開発に無関心になりやすい 要検討 疎結合という甘美な響きの裏にはそれ相応のコストが潜む。 中小規模(予算, 人数)の場合、スケジュール・コストの面で見合わないことがある 10
  5. Laravel での SPA Inertia.js を使うと… • 直接 Vue などのJSコンポーネントを描画できる •

    セットした変数を JS 側で直接受け取れる 変数を直接渡せる 15 ・API必要なし ・JSONエンコード必要なし class UsersController { public function index() { $users = User::active() ->orderByName() ->get(['id', 'name', 'email']); return Inertia::render('Users', [ 'users' => $users ]); } } <script setup> import Layout from './Layout' import { Link, Head } from '@inertiajs/vue3' defineProps({ users: Array }) </script> <template> <Layout> <Head title="Users" /> <div v-for="user in users" :key="user.id"> <Link :href="`/users/${user.id}`"> {{ user.name }} </Link> <div>{{ user.email }}</div> </div> </Layout> </template>
  6. Laravel での SPA Inertia.js を使うと… • 直接 Vue などのJSコンポーネントを描画できる •

    セットした変数を JS 側で直接受け取れる 変数を直接渡せる 16 ・API必要なし ・JSONエンコード必要なし まるでBladeファイルを書くように、フロントエンドの開発ができる! class UsersController { public function index() { $users = User::active() ->orderByName() ->get(['id', 'name', 'email']); return Inertia::render('Users', [ 'users' => $users ]); } } <script setup> import Layout from './Layout' import { Link, Head } from '@inertiajs/vue3' defineProps({ users: Array }) </script> <template> <Layout> <Head title="Users" /> <div v-for="user in users" :key="user.id"> <Link :href="`/users/${user.id}`"> {{ user.name }} </Link> <div>{{ user.email }}</div> </div> </Layout> </template>
  7. Inertia.js Inertia.js は Laravel8 から採用され Breeze で簡単にセットアップが可能 18 curl -s

    "https://laravel.build/laravel-inertia-vue-app?with=pgsql" | bash cd laravel-inertia-vue-app # Dockerコンテナ起動 ./vendor/bin/sail up -d # Breezeのインストール ./vendor/bin/sail composer require laravel/breeze --dev ./vendor/bin/sail artisan breeze:install vue # マイグレーションコマンド実行 ./vendor/bin/sail artisan migrate # Viteの開発サーバー起動 ./vendor/bin/sail npm install ./vendor/bin/sail npm run dev
  8. Inertia.js どういう動きをしているか… 21 ポイント① : Inertia が提供する <Link> コンポーネント ・<Link>をクリックすると

    、通常の遷移を XHR 経由に変える ・ヘッダーに “X-Inertia : true” が付与される
  9. Inertia.js どういう動きをしているか… 22 ポイント① : Inertia が提供する <Link> コンポーネント ・<Link>をクリックすると

    、通常の遷移を XHR 経由に変える ・ヘッダーに “X-Inertia : true” が付与される ポイント② : Laravel は Inertia からのアクセスの場合、DOMではなくJSONを返す Laravel は ヘッダー “X-Inertia : true” が ・ない場合 : 定義されたViewをDOMとして返す ・ある場合 : DOMは返さず、setされた変数をJSON化して、JSONとして返す ※ https://github.com/inertiajs/inertia-laravel/blob/master/src/Response.php
  10. Inertia.js どういう動きをしているか… 26 初回アクセス・アドレスバーから直接遷移した場合 < 普通のアクセスだから、DOMとデータ全部渡すぞ REQUEST GET: http://example.com/dashboard Accept:

    text/html, application/xhtml+xml RESPONSE HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 <html> <head> <title>My app</title> <link href="/css/app.css" rel="stylesheet"> <script src="/js/app.js" defer></script> </head> <body> <div id="app" data-page='{"component":“Dashboard","props"...}'></div> </body> </html>
  11. Inertia.js どういう動きをしているか… 29 2回目以降に<Link>からアクセスした場合 <Link>経由だから、リクエストをXHRに変えたよ > X-Inertia ヘッダーもつけておいたよ > import

    { Link } from '@inertiajs/vue3'; <Link :href="route('dashboard')">Dashboard</Link> REQUEST GET: http://example.com/dashboard Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5
  12. Inertia.js どういう動きをしているか… 30 2回目以降に<Link>からアクセスした場合 < X-Inertia があるから、JSONで返すぞ <Link>経由だから、リクエストをXHRに変えたよ > X-Inertia

    ヘッダーもつけておいたよ > REQUEST GET: http://example.com/dashboard Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5
  13. Inertia.js どういう動きをしているか… 31 2回目以降に<Link>からアクセスした場合 < X-Inertia があるから、JSONで返すぞ <Link>経由だから、リクエストをXHRに変えたよ > X-Inertia

    ヘッダーもつけておいたよ > REQUEST GET: http://example.com/dashboard Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5 RESPONSE HTTP/1.1 200 OK Content-Type: application/json Vary: Accept X-Inertia: true { "component": "Dashboard", "props": { "canLogin": true, "canRegister": false, "laravelVersion": "10.13.5", "phpVersion": "8.2.7", "event": "phpconfuk2023" }, "url": "/dashboard", "version": "c32b8e4965f418ad16eaebba1d4e960f" }
  14. Inertia.js どういう動きをしているか… 32 2回目以降に<Link>からアクセスした場合 < X-Inertia があるから、JSONで返すぞ <Link>経由だから、リクエストをXHRに変えたよ > X-Inertia

    ヘッダーもつけておいたよ > < Dashboardコンポーネントだけを 受け取ったJSONの内容で書き換えるよ REQUEST GET: http://example.com/dashboard Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5 RESPONSE HTTP/1.1 200 OK Content-Type: application/json Vary: Accept X-Inertia: true { "component": “Dashboard", "props": { "canLogin": true, "canRegister": false, "laravelVersion": "10.13.5", "phpVersion": "8.2.7", "event": "phpconfuk2023" }, "url": "/dashboard", "version": "c32b8e4965f418ad16eaebba1d4e960f" }
  15. 仕事で使って感じた メリット・デメリット • 管理が楽 • • • 38 メリット ・APIスキーマ用、フロントエンド用のリポジトリなどの管理を気にせず、

    1つのリポジトリ内でアプリケーションが完結する。 ・1つのリポジトリにアプリケーションがあるため、 CI/CD, E2E テストもMPAのLaravelと同様の手順で行える。
  16. 仕事で使って感じた メリット・デメリット • • SPAとは思えない開発速度 • • 39 メリット ・変数の受け渡しがスムーズ

    APIスキーマを定義して…フロントと共有して…の必要がない。 ・Laravel側のルーティング, 認証などをそのまま使えるため、 フロント側は画面の作りにのみ集中できる。
  17. 仕事で使って感じた メリット・デメリット • • • それぞれの開発が見えやすい • 40 メリット ・同じリポジトリ内で作業をしているため、バックエンド・フロントエンド担当

    それぞれの作業で何をやっているのかよく分かる。 → 仕様・知見の共有面でも良かった。 ・簡単な修正ならお互いに直せる。(Ex. この値欲しい, ここの表示こうしたい、など)
  18. 仕事で使って感じた メリット・デメリット • • • • エコシステム, Inertiaが用意しているコンポーネントが優秀 41 メリット

    ・Breeze で容易にセットアップが出来る。 ・Form, バリデーションとエラーの表示, ファイルアップロードなど、 SPAで面倒になりがちなところが Inertia.js 側で用意されている。
  19. 仕事で使って感じた メリット・デメリット 44 デメリット(注意点) ・(設計によるが)Controllerに画面表示に必要な変数を全てセットするため、 APIの場合と比べて単体テストがゴチャゴチャする。 → MPA方式の時と同様 ・Inertia 用のPHPUnitで実行できるAssertがあるため、埋め込みのJSよりはテストが書ける

    • Laravelの単体テストはAPIの方が書きやすい • • <?php use Inertia¥Testing¥AssertableInertia as Assert; class PodcastsControllerTest extends TestCase { public function test_can_view_podcast() { $this->get('/podcasts/41') ->assertInertia(fn (Assert $page) => $page ->component('Podcasts/Show') ->has('podcast', fn (Assert $page) => $page ->where('id', $podcast->id) ->where('subject', 'The Laravel Podcast') ->has('seasons', 4) ->has('seasons.4.episodes', 21) ->has('host', fn (Assert $page) => $page ->where('id', 1) ->where('name', 'Matt Stauffer') ) ) ); } }
  20. 仕事で使って感じた メリット・デメリット 45 デメリット(注意点) ・APIスキーマがあれば…という場面は実際何度もあった ・フロントエンドがモックサーバで開発が出来ない ・リクエスト, レスポンス, モデルの型チェック →

    16:30~ Urata Daiki のレギュラートークの内容でカバー ・長期的, 大人数で開発する際には、APIスキーマがあるべきと改めて思った • • APIスキーマによるモック, 型の恩恵は受けれない •
  21. まとめ Inertia.js • バックエンドとフロントエンドをあえて密結合(モノリス)にする • 複雑さを感じることなく、スピーディーにSPAを構築するためのプラグイン 向いていると感じたユースケース • MVPのように、まずはスピーディーに動くアプリケーションを作る場合 •

    データ構造はシンプルだが、画面の動きはリッチにしたい場合 • 中小規模(予算, 人数)のアプリケーション お気軽SPA開発をぜひ体験してみてください! 48 対応しているバックエンド 対応しているフロントエンド