Laravel(ver.10)+React+TypeScriptでSPAを構築

Laravel(ver.10)でフロントエンドをTtpeScriptで書くReactの環境構築方法を備忘録も兼ねて紹介する。

## Laravelのインストール
まずは、ターミナルでプロジェクトを作りたい所に移動してLaravelのインストール
```
$ composer create-project laravel/laravel (プロジェクト名)
```

## React(TypeScript)使用に必要なモジュールのインストール
laravelのプロジェクトができたら、プロジェクトフォルダに移動してReactをインストールしていく

Node.jsのパッケージを管理するnpmをインストール
```
npm install
```


TypeScriptのReactをインストール
```
npm install -D react react-dom @types/react @types/react-dom
```
ViteでReactを利用するために@vitejs/plugin-reactのインストール
```
npm install -D @vitejs/plugin-react
```
TypeScriptのインストール
```
npm install -D typescript
```

React用のTypeScriptの設置ファイル作成（tsconfig.json）
```
npx tsc --init --jsx react-jsx
```

## Viteの設定
laravelプロジェクトの作成時に、vite.config.jsというファイルが作成されている。
このファイルの拡張子を".js"→".ts"に変更しvite.config.tsにする。
続いて中身を下記のように変更
```typescript:vite.config.ts
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

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

```

## TypeScriptのビューの画面表示実装

resourceディレクトリに"ts"という名前のディレクトリを新規に作成。
その中にindex.tsxというファイルを作成しその中を下記のように編集。
```typescript:index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';


const container = document.getElementById('app');
const root = createRoot(container!); 

root.render(
    <>
        <div>
            Hello, world!
        </div>
    </>

);
```
続いて、resourceディレクトリ>viewsディレクトリにindex.balde.phpというファイルを作成して
中身を下記のように編集。

```PHP:index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>laravel+TypeScript</title>
    @viteReactRefresh
    @vite([
    'resources/css/app.css',
    'resources/ts/index.tsx',
    ])
</head>
<body>
    <div id="app"></div>
</body>
</html>

```

routesディレクトリのweb.phpファイルを下記のように書き換える。
```PHP:web.php
<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/



Route::get('{any}', function () {
    return view('index');
})->where('any','.*');
```

ローカルサーバーを立ち上げて確認してみる。
ターミナルをも１つ立ちげてプロジェクトの階層に移動。
(VScodeを使っているならVscodeのターミナルでもOK)
片方のターミナルで
```
php artisan serve
```
もう片方のターミナルで
```
npm run dev
```
を実行する。http://127.0.0.1:8000にアクセスして下記の画面になればOK
![hell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/c179b807-ff5a-3098-1fcc-112b2be63423.png)
ここまでで、最低限の環境構築が完了

## ルーティングを試す
ページの切り替えを実装する。
react routerでルーティングを行うためインストール。
また、今回はver.6を使う。(ネットの情報ではver.5の情報が多いが
コードの書き方がver.6と違う、ver.5の書き方だと動作しない。)
```
npm i -D react-router-dom @types/react-router-dom
```
切り替えのページ(コンポーネント)を作成する。
今回は、NavとHomeとAboutの３つ作ってみる。
tsディテレクトリにNav.tsxとHome.tsxとAbout.tsxを作成し、それぞれ下記のように編集。
```typescript:Nav.tsx
import { FC } from "react"
import { Link } from 'react-router-dom';

export const Nav: FC = () => {


    return (
        <header>
            <h1>Nav</h1>
                
            <ul>
                <li><Link to="home">Home</Link></li>
                <li><Link to="about">About</Link></li>
            </ul>
        </header>
    )

}
```
```typescript:Home.tsx

import { FC } from "react"


export const Home: FC = () => {


    return (
        <div >
            <h1>Home</h1>
            <p>Homemコンポーネントです。</p>
        </div>
    )

}
```
```typescript:About.tsx
import { FC } from "react"


export const About: FC = () => {


    return (
        <div >
            <h1>About</h1>
            <p>Aboutコンポーネントです。</p>
        </div>
    )

}
```
続いて、index.tsxを下記のように書き換える
```typescript:index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

import { Nav } from './Nav';
import { Home } from './Home';
import { About } from './About';


const container = document.getElementById('app');
const root = createRoot(container!);

root.render(

    <React.StrictMode>

    <BrowserRouter>
    <Nav />
      <Routes>
        <Route path="/home" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>

);
```

これで再びローカルサーバーを立ち上げて確認してみる。
下記のようになる。
![なb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/cb58efaf-fe45-7327-3e96-60a870ee9478.png)
ここで、Homeをクリックするとページが切り替わる。
![hm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/ee6628cc-892f-25af-d780-468168bcfc9f.png)
Aboutも同様。
![ab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332453/7d5c4bb0-4cca-335b-e993-6ab93c407985.png)

以上で完了。