I recently started a new Laravel project, and as usual, I'm using Inertia, React, and TypeScript. It's been a while since I set up a project from scratch, so I thought I'd put together a quick guide with all the steps you need to get off the ground. If you're like me and prefer this stack, or maybe you're interested in trying it out for the first time, this should help you get started. Let's dive in!
First up, let’s get a fresh Laravel installation to work with. Create a new Laravel app using the following command:
laravel new my-app
Once your project is created, you’ll need to install the Inertia.js Laravel adapter. This allows your Laravel backend to handle requests and serve pages using Inertia:
composer require inertiajs/inertia-laravel
Next, create a root template file where Inertia will connect and manage your front-end page changes without a full browser refresh. I usually put this in resources/views/app.blade.php
:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> @viteReactRefresh @vite('resources/js/app.tsx') @inertiaHead </head> <body> @inertia </body> </html>
Now, set up the Inertia middleware to handle the requests seamlessly. This command will create the necessary middleware for you:
php artisan inertia:middleware
Add the newly created HandleInertiaRequests
middleware to your project's middleware stack in bootstrap/app.php
so it can process requests properly:
use App\Http\Middleware\HandleInertiaRequests; ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ HandleInertiaRequests::class, ]); });
I use nvm
to manage Node.js versions effectively. To specify the Node.js version for this project, create a .nvmrc
file with the current LTS version. At the moment, it’s lts/iron
:
lts/iron
The next part is setting up Inertia with TypeScript. This is essential if you want type safety in your JavaScript/React code. Begin by installing necessary dependencies:
npm install @inertiajs/react react react-dom npm install --save-dev typescript @vitejs/plugin-react @types/react @types/react-dom
After installing these, configure Vite, the build tool Laravel uses. Update the vite.config.js
file like this:
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/js/app.tsx'], refresh: true, }), react(), ], resolve: { alias: { '@': '/resources/js', }, }, });
Now, let’s configure TypeScript by creating a tsconfig.json
file with these options, which set up your compiler environment for handling JavaScript and TypeScript together:
{ "compilerOptions": { "allowJs": true, "module": "ESNext", "moduleResolution": "bundler", "jsx": "react-jsx", "strict": true, "isolatedModules": true, "target": "ESNext", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "paths": { "@/*": ["./resources/js/*"] } }, "include": ["resources/js/**/*.ts", "resources/js/**/*.tsx", "resources/js/**/*.d.ts"] }
Rename the existing resources/js/bootstrap.js
to resources/js/bootstrap.ts
to align with TypeScript usage.
To allow TypeScript to recognize any global variables or interfaces, create a resources/js/types/global.d.ts
file like this:
import { AxiosInstance } from 'axios'; declare global { interface Window { axios: AxiosInstance; } }
For Vite-specific references, create a resources/js/vite-env.d.ts
with the following content:
/// <reference types="vite/client" />
Rename resources/js/app.js
to resources/js/app.tsx
and populate it with this content to bootstrap your React Inertia app:
import './bootstrap'; import '../css/app.css'; import { createRoot } from 'react-dom/client'; import { createInertiaApp } from '@inertiajs/react'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; const pages = import.meta.glob('./Pages/**/*.tsx', { eager: true }); createInertiaApp({ title: (title) => ${title ? ${title} - : ''}${appName}, resolve: (name) => pages[`./Pages/${name}.tsx`], setup({ el, App, props }) { const root = createRoot(el); root.render(<App {...props} />); }, progress: { color: '#4B5563', }, });
Create a React component called WelcomePage in resources/js/Pages/WelcomePage.tsx
to test that everything is working as expected:
export default function WelcomePage() { return ( <div> <h1>Welcome</h1> <p>This is a welcome page</p> </div> ); }
Finally, update the routes/web.php
file so that it uses this new component when loading the homepage:
use Illuminate\Support\Facades\Route; Route::get('/', function () { return inertia('WelcomePage'); });
Visit your application’s home page, and you should see it load your new React component.
If you got to this point, you're pretty much ready to go. But when I start a new project, I usually install TailwindCSS, Shadcn, Prettier, and Biome.js. So, let me show you how easy it is to install those.
TailwindCSS provides utility-first CSS for styling your project quickly. Follow their guide here: Install Tailwind CSS with Laravel
Optional - To keep your class names neat, install the Prettier plugin for TailwindCSS:
npm install -D prettier-plugin-tailwindcss
Shadcn is a UI component library to help you speed up development. Install it with:
npx shadcn@latest init
First, I always create an .editorconfig
file with the following configuration. Feel free to change the file based on your preferences:
Having consistent formatting makes coding so much easier to manage. Here’s how I set up my project:
First, create an .editorconfig
file to define the coding styles:
root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false [*.{yml,yaml,json}] indent_size = 2 [docker-compose.yml] indent_size = 4 [*.{tsx,ts,js}] indent_size = 2 max_line_length = 80
Install Prettier for automatic code formatting:
npm install --save-dev --save-exact prettier
Create a .prettierrc.json
file like this to configure Prettier:
{ "semi": true, "tabWidth": 2, "printWidth": 80, "singleQuote": true, "trailingComma": "all", "plugins": ["prettier-plugin-tailwindcss"] // Optional }
Biomes provide static analysis and linting for your project. Install Biome:
npm install --save-dev @biomejs/biome npx @biomejs/biome init
Disable Biome’s internal formatter in the biome.json since you’re using Prettier:
{ "formatter": { "enabled": false } }
I don't personally use Biome's formatter because it doesn't support the TailwindCSS Prettier plugin, and their equivalent plugin isn't good enough.
Having said that, Biome's fast linting engine is a solid alternative to ESLint, which can keep your code clean and catch potential issues as you code.
And that's it! You've now set up a Laravel app with Inertia, React, and TypeScript. I hope this guide makes things a bit easier for you. Adding TailwindCSS, Shadcn, Prettier, and Biome means your project is off to a great start, and you've got some great tools to use as you go.
Remember, everyone does things a little differently, so feel free to change things up to fit your style.
Happy coding!