This project combines the power of Laravel, InertiaJS, React, and TypeScript to create a modern web application with a seamless user experience.
- Laravel: A PHP framework for elegant backend development
- InertiaJS: Bridges the gap between server-side rendering and SPAs
- React: A JavaScript library for building user interfaces
- TypeScript: Adds static typing to JavaScript for better code quality
composer create-project laravel/laravel your-project-name
cd your-project-namecomposer require inertiajs/inertia-laravelCreate a file resources/views/app.blade.php with the following content:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
/>
@vite('resources/ts/app.tsx') @inertiaHead
</head>
<body>
@inertia
</body>
</html>php artisan inertia:middlewareAdd the middleware to bootstrap/app.php:
<?php
use App\Http\Middleware\HandleInertiaRequests;
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// ...other singleton instances
$app->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
HandleInertiaRequests::class,
]);
});
return $app;npm install @inertiajs/react
npm install @types/react @types/react-dom typescript
npm install tailwindcssCreate tailwind.config.js:
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./resources/**/*.blade.php",
"./resources/**/*.tsx",
"./resources/**/*.ts",
],
theme: {
extend: {},
},
plugins: [],
};Create resources/css/app.css:
@import "tailwindcss";Create resources/ts/app.tsx:
import "../css/app.css";
import { createInertiaApp } from "@inertiajs/react";
import { createRoot } from "react-dom/client";
import React from "react";
import Layout from "./layout";
declare global {
interface ImportMeta {
glob: (
pattern: string,
options?: { eager: boolean }
) => Record<string, any>;
}
}
createInertiaApp({
resolve: (name) => {
const pages = import.meta.glob("./pages/**/*.tsx", { eager: true });
const pagePath = `./pages/${name}.tsx`;
let page: any = pages[pagePath];
if (!page) {
console.error(`Page not found: ${name} (${pagePath})`);
throw new Error(`Page not found: ${name}`);
}
page.default.layout =
page.default.layout || ((page: any) => <Layout children={page} />);
return page;
},
setup({ el, App, props }) {
if (!el) {
return;
}
createRoot(el).render(<App {...props} />);
},
}).then(() => {
console.log("Inertia app initialized");
});Update vite.config.js:
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
laravel({
input: ["resources/css/app.css", "resources/ts/app.tsx"],
refresh: true,
}),
react(),
],
});Create resources/ts/layout.tsx:
import React from "react";
export default function Layout({ children }: { children: React.ReactNode }) {
return <main className="bg-black-base text-white">{children}</main>;
}Create resources/ts/pages/index.tsx:
import { useState } from "react";
const Index = () => {
const [counter, updateCounter] = useState<number>(0);
return (
<div className="min-h-screen flex items-center justify-center">
<div className="bg-white rounded-lg p-8 shadow-md text-center max-w-md w-full">
<h1 className="text-2xl font-semibold text-gray-800 mb-4">
Counter
</h1>
<button
className="px-5 py-2 bg-blue-500 text-white font-medium rounded-md hover:bg-blue-600 transition-colors"
onClick={() => updateCounter((prevState) => prevState + 1)}
>
Count: {counter}
</button>
</div>
</div>
);
};
export default Index;Update routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('index', []);
});npm install @vitejs/plugin-react# Terminal 1 - Start Laravel development server
php artisan serve
# Terminal 2 - Build and watch assets
npm run devVisit http://localhost:8000 to see your application running.
resources/
├── css/
│ └── app.css
├── ts/
│ ├── app.tsx # Main entry point
│ ├── layout.tsx # Default layout
│ └── pages/
│ └── index.tsx # Example page
└── views/
└── app.blade.php # Main template