Setting up a ReactJS + Laravel project

Combining Laravel, a powerful PHP framework, with ReactJS, a popular front-end library, can significantly enhance the capabilities and performance of your applications. In this guide, I’ll walk you through setting up a project with these technologies. Let’s dive in!
Info
If you just want to get the code, this post is implemented on a GitHub repo that you can clone.
Prerequisites
Before we get started, make sure you have the following:
- A basic understanding of JavaScript, PHP, and using the command line.
- Node.js and Composer installed on your computer.
- A code editor like VS Code (highly recommended!).
Step 1: Setting up the Project Folder
First, let’s create a new Laravel project. Open your terminal and run:
composer create-project laravel/laravel example-appThis command will create a new Laravel project in a folder named example-app. Next, navigate into the project directory:
cd example-appNote
This is now our project root. Unless specifically stated, all bash commands are expected to run from this directory. Also, you should open yuor code editor into this directory.
Step 2: Creating the React App
Now, let’s set up the front-end with React using Vite, a super-fast build tool. Run the following command to create the React app in a directory called frontend:
yarn create vite frontend --template react-tsThis will scaffold a new React app with TypeScript support. After that, navigate into the frontend directory and install the necessary dependencies:
cd frontend
yarn installStep 3: Configuring Vite
We need to configure Vite to work nicely with our Laravel backend. Install the node types for intellisense:
yarn add -D @types/nodeOpen the frontend/vite.config.ts file and update it with the following content:
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig(({ mode, command }) => {
// Load variables that change between environments
const env = {
...loadEnv(mode, process.cwd(), ""),
...loadEnv(mode, path.join(__dirname, ".."), ""),
};
const BASE_URL = new URL(noTrailingSlash(env.APP_URL));
return {
base: command === "serve" ? "" : noTrailingSlash(BASE_URL.pathname) + "/public/build/",
plugins: [react()],
define: {
global: "globalThis",
BASE_URL: command === "serve" ? undefined : JSON.stringify(BASE_URL),
},
server: {
port: 3000,
proxy: {
"/api": {
target: BASE_URL.toString(),
changeOrigin: true,
secure: false,
},
},
},
resolve: {
alias: {
// Allow accessing the `src` directory from anywhere in the tree using `@src`
"@src": path.resolve(__dirname, "./src"),
},
},
build: {
outDir: "../public/build",
},
};
});
// Remove trailing slash if any
function noTrailingSlash(str: string) {
return /\/$/.test(str) ? str.substring(0, str.length - 1) : str;
}Why Proxying?
During development, Vite runs a development server on port 3000, while Laravel’s server runs on port 8000. Proxying helps route API requests from the React front-end to the Laravel back-end seamlessly.
Step 4: Setting Up Aliases
Aliases make importing modules easier. Instead of writing long relative paths, you can use short and meaningful aliases. Update your frontend/tsconfig.app.json to include the alias configuration:
{
"compilerOptions": {
// ...
/* Import path resolution */
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
},
}
}Now, you can import modules like this:
const FancyContainer = import("@src/Components/FancyContainer");Step 5: Configuring Laravel for API Routing
Note
You can skip this step if not using Apache server.
Updating .htaccess
If using an Apache server for your web app, we’ll need to tweak Laravel’s .htaccess file to ensure our routes are handled correctly:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Redirect non-API requests to root
RewriteCond %{REQUEST_URI} .+
RewriteCond %{REQUEST_URI} !api
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^ public/handler.php [L]
# Send any file Requests not in the public folder to Front Controller
RewriteCond %{REQUEST_URI} !public/
RewriteRule \.\w+$ index.php [L]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
<FilesMatch "\.(eot|ttf|otf|woff|woff2)">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>Creating index.php
Create a file named index.php at the root of your project and add the following:
<?php
include './public/index.php';
This ensures Laravel can handle incoming requests properly.
Step 6: Setting Up the Public Directory
In the public directory, we need to handle requests and provide fallback options if the build hasn’t been run yet.
Adding fallback.php
Create a file named fallback.php in the public directory with the following content:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,maximum-scale=1"
/>
<meta name="theme-color" content="#000000" />
<title>Build Required!</title>
<style type="text/css">
body {
text-align: center;
padding: 150px;
}
h1 {
font-size: 40px;
}
body {
font: 20px Helvetica, sans-serif;
color: #333;
}
#article {
display: block;
text-align: left;
width: 650px;
margin: 0 auto;
}
a {
color: #dc8100;
text-decoration: none;
}
a:hover {
color: #333;
text-decoration: none;
}
</style>
</head>
<body>
<div id="article">
<h1>Welcome Developers!</h1>
<div>
<p>
In order to view the full webpage, you will need to run the build
script. Please follow the steps in the <a href="#">Project Wiki</a> to
set up your development environment and build the website
</p>
<p>
Please note that any changes made to the source code will need to be
built again for the changes to be reflected on the website.
</p>
</div>
</body>
</html>Adding handler.php
Create a file named handler.php in the public directory with the following content:
<?php
$build_html = public_path("build/index.html");
if (file_exists($build_html)) {
include $build_html;
} else {
include public_path("fallback.php");
}
?>These files ensure that users see a friendly message if the build hasn’t been run yet.
Loading the Handler page
Change the contents of the resources/views/welcome.blade.php file to the following:
<?php
include public_path("handler.php"); ?>Step 7: Linting and Code Formatting
To keep our code clean and consistent, we’ll set up ESLint and Prettier. First, install Prettier and ESLint:
yarn add -D prettier @prettier/plugin-php eslint> [ESLint](https://eslint.org/) is a static analyzer for your Javascript/Typescript code to quickly find problems. On the other hand, [Prettier](https://prettier.io/) is an opinionated code formatter. Install extensions for the two in your code editor
ESLint Configuration
Create a .eslintrc.cjs file in the frontend directory with the following content:
module.exports = {
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
parser: "@babel/eslint-parser",
env: {
node: true,
es6: true,
browser: true,
},
globals: {
BASE_URL: true,
},
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
requireConfigFile: false,
ecmaFeatures: {
jsx: true,
modules: true,
experimentalObjectRestSpread: true,
},
babelOptions: {
presets: ["@babel/react"],
},
project: true,
tsconfigRootDir: __dirname,
},
rules: {
"no-unused-vars": [
"error",
{
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
"no-empty": ["error", { allowEmptyCatch: true }],
"react/prop-types": [2, { skipUndeclared: true }],
},
};Prettier Configuration
Create a .prettierrc.json file in the project directory:
{
"semi": true,
"tabWidth": 4,
"useTabs": false,
"printWidth": 100,
"braceStyle": "1tbs",
"trailingComma": "es5"
}This setup ensures our code looks great and follows best practices automatically.
Step 8: Updating package.json
Next, we need to update the package.json file in the root of your project. This file helps manage the project’s scripts and dependencies. Add the following scripts to the scripts section:
{
"name": "example-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "cd frontend && yarn dev",
"build": "cd frontend && yarn build",
"postinstall": "cd frontend && yarn install"
},
"dependencies": {
// Your dependencies here
},
"devDependencies": {
// Your devDependencies here
}
}These scripts help streamline your workflow:
devstarts the development server.buildcompiles the React app.postinstallensures the front-end dependencies are installed.
Step 9: Environment Variables
Set the APP_URL variable in your .env file to http://localhost:8000.
Final Step: Running the Project
We’re almost there! Some clean up, delete the vite.config.js file at the root of the project. Then open two terminal windows. In the first one, start the Laravel server:
php artisan serveIn the second terminal, start the Vite development server:
yarn run devNow, open your browser and navigate to http://localhost:3000 to see your application in action.
And there you have it! You’ve successfully set up a project with React and Laravel. I hope this guide was helpful and easy to follow. Happy coding! If you run into any issues or have questions, feel free to leave a comment below or reach out to me on Twitter @benz_stevox. You can also check out the GitHub repo for more details.
