LoginSignup
5

posted at

updated at

Laravel9 × React InertiaでTypeScript開発

はじめに

Laravel9 × React Inertiaの組み合わせでTypeScript環境を構築したかったのですが、思いのほか手間取ったので、簡単に手順を残しておきます。

開発環境

  • PC -> M1 MacBook Pro 2021
  • php -> 8.1.5
  • Laravel -> 9.20.0
  • vite -> 2.9.14
  • Docker Desktop

Laravel環境構築

Laravel Sailを使ってLaravelの環境をローカルに構築。

$ curl -s "https://laravel.build/アプリ名?with=mysql" | bash

$ cd アプリ名

$ ./vendor/bin/sail up -d

Inertia React環境構築

認証機能も使用したいためbreezeをreact指定でインストール。

$ ./vendor/bin/sail composer require laravel/breeze --dev

$ ./vendor/bin/sail artisan breeze:install react

$ npm install && npm run dev

TypeScript環境の初期設定

必要そうなパッケージをインストール

npm install -D typescript @types/node @types/react @types/react-dom 

app.jsの編集

app.jsの拡張子をtsxに変更して、コードを下記のように修正。

import "./bootstrap";
import "../css/app.css";

import React from "react";
import { render } from "react-dom";
import { createInertiaApp } from "@inertiajs/inertia-react";
import { InertiaProgress } from "@inertiajs/progress";
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";

const appName =
    window.document.getElementsByTagName("title")[0]?.innerText || "Laravel";

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) =>
        resolvePageComponent(
            `./Pages/${name}.tsx`,
            import.meta.glob("./Pages/**/*.tsx")
        ),
    setup({ el, App, props }) {
        return render(<App {...props} />, el);
    },
});

InertiaProgress.init({ color: "#4B5563" });

vite-env.d.tsの追加

vite-env.d.tsファイルをapp.tsxと同じ階層に作成して、下記のコードを記述。

interface ImportMeta {
    readonly glob: any;
}
declare var route: any;

tsconfig.jsonの作成

下記のコードをターミナルで実行すると、tsconfig.jsonが作成される。

$ tsc --init   

tsconfig.jsonの中身を下記のコードに書き換える。

{
    "compilerOptions": {
        "baseUrl": ".",
        "target": "ESNext",
        "useDefineForClassFields": true,
        "lib": ["DOM", "DOM.Iterable", "ESNext"],
        "allowJs": false,
        "skipLibCheck": true,
        "esModuleInterop": false,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "ESNext",
        "moduleResolution": "Node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "paths": {
            "@/*": ["resources/js/*"]
        }
    },
    "include": ["resources/js/**/*"],
    "references": [{ "path": "./tsconfig.node.json" }]
}

tsconfig.node.jsonの作成

tsconfig.jsonと同じ階層にtsconfig.node.jsonを作成して、下記のコードを記述。
TypeScriptの設定ファイルがtsconfig.jsonとtsconfig.node.jsonで二つあるのは、TypeScriptを実行する環境が二つあるから、とのこと。

{
    "compilerOptions": {
        "composite": true,
        "module": "esnext",
        "moduleResolution": "node"
    },
    "include": ["vite.config.ts"]
}

app.blade.phpの内容を編集

app.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 inertia>{{ config('app.name', 'Laravel') }}</title>

        <!-- Fonts -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">

        <!-- Scripts -->
        @routes
        @viteReactRefresh
        @vite('resources/js/app.tsx')
        @inertiaHead
    </head>
    <body class="font-sans antialiased">
        @inertia
    </body>
</html>

vite.config.jsの編集

vite.config.jsの拡張子をtsに変更した後に、コードを下記の内容に修正。

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.tsx",
            refresh: true,
        }),
        react(),
    ],
});

tailwind.config.jsの内容を変更

const defaultTheme = require("tailwindcss/defaultTheme");

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        "./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php",
        "./storage/framework/views/*.php",
        "./resources/views/**/*.blade.php",
        "./resources/js/**/*.tsx",
    ],

    theme: {
        extend: {
            fontFamily: {
                sans: ["Nunito", ...defaultTheme.fontFamily.sans],
            },
        },
    },

    plugins: [require("@tailwindcss/forms")],
};

認証機能コンポーネントをTypeScript仕様に変更

次にbreezeによって生成されたAuth用コンポーネントを全てTypeScript仕様に書き換える必要があります。これはかなり面倒なので、下記のGitHubリポジトリからコードを持ってくることをオススメします。
resources/jsフォルダ配下のComponents・Layouts・Pagesフォルダにある全ファイルを、下記のリポジトリのものに置き換えてください。
これが終われば設定完了です。

viteでの型チェックについて

ここでちょっとした注意点が1つ。ViteってTypeScriptを使うことはできるのですが、型チェックは実行してくれないんですよね...

Vite は .ts ファイルをインポートすることをサポートしています。
Vite は .ts ファイルに対してトランスパイルをするだけで、型チェックは 実行しません。

正直、これはかなり違和感がありました。npx create-react-appで作ったアプリは型が間違っていると、処理が停止してブラウザ上にデカデカとエラーが出たりしたのですが、Viteではそういうのが全くないです。
写真のようにどっからどう見てもやばい型エラーがあっても、何事もなかったかのようにアプリは動き続けます。

スクリーンショット 2022-07-16 21.29.14.png
スクリーンショット 2022-07-16 21.30.06.png

まあ、VScodeなどを使っていれば、赤波線が入ったりするので、そこまで心配するほどのことではないのですが、最初はやはり違和感がありました。
一応、tsc --noEmitを実行すれば、こんな感じでチェックはできるので、GitHubにpushする前などには、実行して確認するのがベストだと思います!
スクリーンショット 2022-07-16 21.34.00.png

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5