個人でやってるサイトで、Reactの学習も兼ねて色々触ろうかと思うなかで、初めは別機能の部分を新規でNextJSで作ろうと思っていたのですが、一部機能だけとかだとログイン周りとかの処理が面倒で、そのままテンプレだけReactに移行できればと思って行いました。
というので、色々調べていたらLaravel->Reactはできそうというので、webpackを使うでもなく素bladeで作成されたプロジェクトの一部をReact化しました。
環境
Laravel 6だったところから、9にバージョンアップしたもの
なのでLaravelではViteがデフォルトになってますが、新規で作ってないのでvite.configとかもない状態でした
Nodeとyarnを入れる
この辺はメインの話ではないので雑に。下記から手に入れます。node18.14で実行しています。
ちなみに今回は関係ないですが、普段バージョン切り替えなどが必要なこともあるため私は n
を利用しています。
yarnはこちら
Viteの導入
素のBladeと書いたので、Viteが動かない状態です。
各種パッケージを追加します。もしかしたらLaravel9ではもともとpackage.jsonに記載されているかもしれません。
yarn add -D vite laravel-vite-plugin @vitejs/plugin-react
設定ファイルはLaravel9から作っていれば初期からファイルがありそうですが、アップデートしたものなので自分で置きました。
またここで、 @vitejs/plugin-react
を利用するため記載内容が少し異なります。
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
laravel({
input: ["resources/js/app.jsx"],
refresh: true,
}),
react()
]
});
下のpackage.jsonも同様で、必要に応じて追記・上書きします。
webpackやそれ以外ですでに、devやbuildを使っているのであれば、別の名前をつけましょう。
"scripts": {
"dev": "vite",
"build": "vite build",
}
Inertiaの導入
LaravelのデータをReactにわたす場合は、Inertiaを使うようです
PHP側(サーバー側)
composer require inertiajs/inertia-laravel
Bladeは完全には消えず、 app.blade.php
に下記のようなものを置く必要があるようです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
@viteReactRefresh
@vite('resources/js/app.jsx')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
すでに app.blade.php
を利用済みなら変更は可能で、上のsetupページと下記のリンクが参考になりそうです。
https://stackoverflow.com/questions/63926485/change-inertiajs-laravel-default-rootview
php artisan inertia:middleware
これで Http/Middleware/HandleInertiaRequests.php
というミドルウェアのファイルが追加されます。多分コマンドを使うことでAppのnamespaceがちゃんと設定されるようです。
ちなみに、こいつを git add
し忘れて本番で動かず困りましたw
このMiddlewareをKernelに追加
'web' => [
// ...
\App\Http\Middleware\HandleInertiaRequests::class,
],
\App
の部分は独自のnamespaceを利用している場合は適宜変える必要があります。
JS側(クライアント側)
yarn add @inertiajs/react
ドキュメントには記載する内容は書いてあるが、どこに置くかが書いてないですが、上で設定値として記載した resource/js/app.jsx
に置きます。
ドキュメントでは resource/js/app.js
って書いてありますが、<App />
を使っているため、jsxである必要があります。
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'
createInertiaApp({
resolve: name => {
// TypeScriptなら.tsx
const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
return pages[`./Pages/${name}.jsx`]
},
setup({ el, App, props }) {
createRoot(el).render(<App {...props} />)
},
})
実際にはTypeScriptにしたり、PostCSSとかSASSの導入、Storybookの導入などなどいろいろパッケージは必要だと思います。ここでは主題ではないので飛ばします。
参考:Jetsteram(かBreeze)
JetstreamでInertia等を導入することもできるようですが、新規のLaravelアプリケーションのみのようなので、今回はInertiaを直接入れています
PHP LaravelのControllerの書き換え
既存のページのview呼び出しを書き換えます。まだ作っていないディレクトリ構造なので適当に。
- return view('dir.template', []);
+ return Inertia::render('Dir/Template', []);
Reactの導入
Reactそのものは入れてない状態なので入れます
yarn add react react-dom
JSX(TSX)の追加
上記で指定したパスにJSXなりTSXを置きます
export default function Template () {
return (
<>
<h1>タイトル</h1>
<div>ほげほげ</div>
</>
)
}
値をテンプレートに渡す
Bladeと同様に、第二引数が渡されます。
return Inertia::render('Dir/Template', ['title' => 'test']);
export default function Template (props) {
return (
<>
<h1>{props.title}</h1>
<div>ほげほげ</div>
</>
)
}
TypeScript使ったほうが型を定められて便利かと思います
起動
yarn dev
アクセス
これでPHPサーバーの該当パスにアクセスすると表示されるはずです。
(自分の場合はlocalhost)
また、jsxのファイルを触るとブラウザ側に自動で反映されるはずです。めちゃ速い!
もちろん他のパスはこれまで通りBladeのVIEWに飛びます。
うまく出ないときは
- WEBブラウザのデベロッパーツールからconsoleエラー確認
- viteを立ち上げたコンソールの確認
- PHP側のエラーの確認
- サーバー側のエラーの確認
あたりの確認になると思います
Controllerの単体テスト
Controllerのactionの返り値は変わるので当然単体テストも変える必要があります。詳細は下記リンクで。
TypeScript対応
この辺はViteの話になってしまうため、雑に記載します。
yarn create vite
とやると初期のプロジェクトが作られます。このときに React
TypeScript
を選べば
tsconfig.json
等必要なファイルが作られるので、それを参考にするのが良いと思います。
おわりに
PHPのときは割とViewでHelper使ったり、ゴリゴリ処理入れたりしがちでしたが、JS(React)で処理する場合はロジックはちゃんとサーバー側に寄せて色々処理し、Viewでは表示に専念させるかたちにするのは大事だと感じました
という点で単にViewだけ切り替えてというのができない場合もありますが、部分的にReact化できるのは移行の面では非常に便利だと感じました。