はじめに
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ではそういうのが全くないです。
写真のようにどっからどう見てもやばい型エラーがあっても、何事もなかったかのようにアプリは動き続けます。
まあ、VScodeなどを使っていれば、赤波線が入ったりするので、そこまで心配するほどのことではないのですが、最初はやはり違和感がありました。
一応、tsc --noEmit
を実行すれば、こんな感じでチェックはできるので、GitHubにpushする前などには、実行して確認するのがベストだと思います!