13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravel9 × React InertiaでTypeScript開発

Last updated at Posted at 2022-07-16

はじめに

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

13
5
1

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
  3. You can use dark theme
What you can do with signing up
13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?