How to set up a new Laravel project

By Luis Güette

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

Setting Up Inertia with TypeScript

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

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

Shadcn is a UI component library to help you speed up development. Install it with:

npx shadcn@latest init

Formatters

First, I always create an .editorconfig file with the following configuration. Feel free to change the file based on your preferences:

.editorconfig

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

Prettier

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
 
}

Linter

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.

Wrapping Up

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!

Luis Güette
Software Developer
Author Image

Interested in speaking with a developer?

Connect with us.
©2024 Kirschbaum Development Group LLC Privacy Policy Terms of Service