Skip to content

Instantly share code, notes, and snippets.

@ux-powered
Last active May 20, 2020 12:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ux-powered/7c7248274e447d1aad48e08444a3c886 to your computer and use it in GitHub Desktop.
Save ux-powered/7c7248274e447d1aad48e08444a3c886 to your computer and use it in GitHub Desktop.
React + Laravel integration guide
{
"presets": [
"@babel/react",
[
"@babel/env",
{
"targets": {
"browsers": [
">= 1%",
"last 2 versions",
"not dead",
"Chrome >= 45",
"Firefox >= 38",
"Edge >= 12",
"Explorer >= 10",
"iOS >= 9",
"Safari >= 9",
"Android >= 4.4",
"Opera >= 30"
]
}
}
]
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-proposal-class-properties"
]
}

Note: Currently HMR not working, but npm run dev and npm run prod commands work fine.

Here is the guide how to integrate react-demo project with a fresh Laravel project. For laravel-starter you can use the same steps with small changes (for example, you will need to copy only react-demo/public/vendor/ directory because others don't exist).

  1. (optional) Install Laravel and create a new project with React boilerplate:
composer global require laravel/installer
composer create-project --prefer-dist laravel/laravel laravel-react

Then execute the next commands within our laravel-react/ directory:
composer require laravel/ui
php artisan ui react
  1. Remove the next directories:
  • resources/js/
  • resources/sass/
  1. Copy audio/, img/, json/ and vendor/ directories from the react-demo/public/ to laravel-react/public/.

  2. Edit laravel-react/package.json file (see attached file) and execute npm i. Take attention on scripts and devDependencies sections. Please be careful and don't miss anything.

  3. Create laravel-react/.babelrc and laravel-react/browserslist files (see attached files).

  4. Copy react-demo/src/ directory to laravel-react/resources/

  5. Create entry-point.js and bootstrap.js files within the laravel-react/resources/src/ (see attached files).

  6. Copy laravel-vue-starter/webpack.config.js to laravel-react/.

  7. Edit your laravel-react/webpack.mix.js (see attached file). If you don't use ThemeSettings plugin, remove all mix.sass(...).sass(...)... calls.

  8. Since our src directory is in the resources directory (one level deeper in the directory tree), within laravel-react/resources/src/vendor/styles/, find all @imports that pointed to the node_modules directory and add '../' to paths. If you're using VS Code, you can do it using "Find in Folder" and the next Regex:

Find regex: ((:?\.\./)+)node_modules
Replace with: ../$1node_modules
  1. Remove laravel-react/resources/views/welcome.blade.php and create laravel-react/resources/views/application.blade.php (see attached file). You can use React starter generator with corrections to Laravel. Note: all files within the public/vendor/ directory must be included directly, without mix() helper. Example:
<link rel="stylesheet" href="/vendor/fonts/fontawesome.css">
<script src="/vendor/js/layout-helpers.js"></script>
  1. Create main laravel-react/app/Http/Controllers/ApplicationController.php (see attached file).

  2. Edit laravel-react/routes/web.php (see attached file).

  3. That's all. Now you can build assets and run the server:

npm run dev
php artisan serve
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="light-style">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Laravel + React Starter</title>
<!-- Main font -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,700i,900" rel="stylesheet" />
<!-- Icons. Uncomment required icon fonts -->
<link rel="stylesheet" href="/vendor/fonts/fontawesome.css">
<link rel="stylesheet" href="/vendor/fonts/ionicons.css">
<link rel="stylesheet" href="/vendor/fonts/linearicons.css">
<link rel="stylesheet" href="/vendor/fonts/open-iconic.css">
<link rel="stylesheet" href="/vendor/fonts/pe-icon-7-stroke.css">
<!-- Core stylesheets -->
<link rel="stylesheet" href="{{ mix('/vendor/css/bootstrap.css') }}" class="theme-settings-bootstrap-css">
<link rel="stylesheet" href="{{ mix('/vendor/css/appwork.css') }}" class="theme-settings-appwork-css">
<link rel="stylesheet" href="{{ mix('/vendor/css/theme-corporate.css') }}" class="theme-settings-theme-css">
<link rel="stylesheet" href="{{ mix('/vendor/css/colors.css') }}" class="theme-settings-colors-css">
<link rel="stylesheet" href="{{ mix('/vendor/css/uikit.css') }}">
<!-- Material ripple -->
<script src="/vendor/js/material-ripple.js"></script>
<!-- Layout helpers -->
<script src="/vendor/js/layout-helpers.js"></script>
<!-- Theme settings -->
<script src="/vendor/js/theme-settings.js"></script>
<script>
window.themeSettings = new ThemeSettings({
cssPath: '',
themesPath: '',
pathResolver: function(path) {
var resolvedPaths = {
// Core stylesheets
//
@foreach (['bootstrap', 'appwork', 'colors'] as $name)
'{{ $name }}.css': '{{ mix("/vendor/css/{$name}.css") }}',
'{{ $name }}-material.css': '{{ mix("/vendor/css/{$name}-material.css") }}',
'{{ $name }}-dark.css': '{{ mix("/vendor/css/{$name}-dark.css") }}',
@endforeach
// UI Kit
'uikit.css': '{{ mix("/vendor/css/uikit.css") }}',
// Themes
//
@foreach (['air', 'corporate', 'cotton', 'gradient', 'paper', 'shadow', 'soft', 'sunrise', 'twitlight', 'vibrant'] as $name)
'theme-{{ $name }}.css': '{{ mix("/vendor/css/theme-{$name}.css") }}',
'theme-{{ $name }}-material.css': '{{ mix("/vendor/css/theme-{$name}-material.css") }}',
'theme-{{ $name }}-dark.css': '{{ mix("/vendor/css/theme-{$name}-dark.css") }}',
@endforeach
}
return resolvedPaths[path] || path;
}
});
</script>
<!-- IE10 polyfills (remove if you don't plan to support IE10) -->
<script>
if (navigator.userAgent.match('MSIE 10.0;')) {
document.write('<script src="https:\/\/cdn.polyfill.io\/v2\/polyfill.min.js?features=Intl.~locale.en"><\/script>');
}
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- Splash screen -->
<div class="app-splash-screen" style="background: #fff; position: fixed; z-index: 99999999; top: 0; right: 0; bottom: 0; left: 0; opacity: 1; -webkit-transition: opacity .3s; transition: opacity .3s;">
<div class="app-splash-screen-content" style="position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);">
<span class="text-large font-weight-bolder">CompanyName</span>
</div>
</div>
<!-- / Splash screen -->
<div id="root"></div>
<script src="{{ mix('/entry-point.js') }}"></script>
</body>
</html>
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ApplicationController extends Controller
{
public function __invoke()
{
return view('application');
}
}
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
>= 1%
last 2 versions
not dead
Chrome >= 45
Firefox >= 38
Edge >= 12
Explorer >= 10
iOS >= 9
Safari >= 9
Android >= 4.4
Opera >= 30
import './bootstrap'
import './index'
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --disable-host-check",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/preset-react": "^7.0.0",
"@loadable/component": "~5.12.0",
"axios": "~0.19.0",
"bootstrap": "~4.4.1",
"chart.js": "~2.9.3",
"classlist.js": "~1.1.20150312",
"core-js": "~2.6.5",
"cross-env": "^7.0",
"custom-event-polyfill": "^1.0.7",
"date-fns": "2.5.1",
"element-dataset": "~2.2.6",
"google-map-react": "~1.1.7",
"jquery": "^3.2",
"ladda": "~2.0.1",
"laravel-mix": "^5.0.1",
"lodash": "^4.17.13",
"moment": "~2.24.0",
"node-sass": "~4.13.1",
"nouislider-react": "~3.3.6",
"numeral": "~2.0.6",
"p-min-delay": "~3.1.0",
"perfect-scrollbar": "~1.5.0",
"plyr": "~3.5.10",
"popper.js": "^1.12",
"raf": "~3.4.1",
"rc-input-number": "~4.5.1",
"react": "~16.13.0",
"react-app-polyfill": "^1.0.6",
"react-autosize-textarea": "~7.0.0",
"react-avatar-editor": "~11.0.7",
"react-beautiful-dnd": "~13.0.0",
"react-big-calendar": "0.24.1",
"react-bootstrap": "~1.0.0-beta.6",
"react-bootstrap-table-next": "~4.0.0",
"react-bootstrap-table2-editor": "~1.4.0",
"react-bootstrap-table2-filter": "~1.3.0",
"react-bootstrap-table2-paginator": "~2.1.0",
"react-bootstrap-table2-toolkit": "~2.1.2",
"react-bootstrap-typeahead": "~3.4.6",
"react-chartjs-2": "~2.9.0",
"react-clipboard.js": "~2.0.13",
"react-color": "~2.18.0",
"react-contextmenu": "~2.13.0",
"react-datepicker": "~2.14.0",
"react-dom": "~16.13.0",
"react-dropzone": "~10.2.1",
"react-flatpickr": "~3.10.0",
"react-id-swiper": "~3.0.0",
"react-idle-timer": "~4.2.8",
"react-image-lightbox": "~5.1.0",
"react-images": "~1.1.0",
"react-ladda": "~6.0.0",
"react-masonry-component": "~6.2.1",
"react-mde": "~8.2.0",
"react-perfect-scrollbar": "~1.5.8",
"react-quill": "~1.3.3",
"react-redux": "~7.2.0",
"react-router-dom": "~5.1.2",
"react-scripts": "~3.4.1",
"react-select": "~3.1.0",
"react-sortable-tree": "~2.7.1",
"react-sortable-tree-theme-file-explorer": "~2.0.0",
"react-sparklines": "~1.7.0",
"react-stepzilla": "~6.0.0",
"react-table": "~7.0.0",
"react-text-mask": "~5.4.3",
"react-toastify": "~5.5.0",
"recharts": "~1.8.3",
"redux": "~4.0.1",
"resolve-url-loader": "^3.1.0",
"sass": "^1.15.2",
"sass-loader": "^8.0.0",
"showdown": "~1.9.0",
"spinkit": "~2.0.1",
"styled-components": "~5.1.0",
"sweetalert2": "~9.10.2",
"sweetalert2-react-content": "~3.0.0",
"swiper": "~5.3.1",
"text-mask-addons": "~3.8.0",
"url-polyfill": "^1.1.8",
"vue-template-compiler": "^2.6.11"
}
}
<?php
use Illuminate\Support\Facades\Route;
Route::get('/{any}', 'ApplicationController')->where('any', '.*');
const { EnvironmentPlugin, IgnorePlugin } = require('webpack')
const mix = require('laravel-mix')
const path = require('path')
/*
|--------------------------------------------------------------------------
| Mix config
|--------------------------------------------------------------------------
*/
mix.options({
postCss: [require('autoprefixer')]
});
/*
|--------------------------------------------------------------------------
| Webpack config
|--------------------------------------------------------------------------
*/
mix.webpackConfig({
plugins: [
new EnvironmentPlugin({
// Application's public url
PUBLIC_URL: ''
}),
new IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ })
],
resolve: {
alias: {
'~': path.join(__dirname, 'node_modules')
}
}
})
/*
|--------------------------------------------------------------------------
| Vendor assets
|--------------------------------------------------------------------------
*/
const sassOptions = {
implementation: () => require('node-sass')
};
// Core stylesheets
mix.sass('resources/src/vendor/styles/rtl/bootstrap.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/bootstrap-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/bootstrap-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/appwork.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/appwork-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/appwork-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/colors.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/colors-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/colors-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/uikit.scss', 'public/vendor/css', sassOptions);
// Themes
mix.sass('resources/src/vendor/styles/rtl/theme-air.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-air-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-air-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-corporate.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-corporate-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-corporate-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-cotton.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-cotton-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-cotton-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-gradient.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-gradient-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-gradient-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-paper.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-paper-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-paper-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-shadow.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-shadow-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-shadow-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-soft.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-soft-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-soft-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-sunrise.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-sunrise-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-sunrise-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-twitlight.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-twitlight-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-twitlight-dark.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-vibrant.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-vibrant-material.scss', 'public/vendor/css', sassOptions)
.sass('resources/src/vendor/styles/rtl/theme-vibrant-dark.scss', 'public/vendor/css', sassOptions);
/*
|--------------------------------------------------------------------------
| Entry point
|--------------------------------------------------------------------------
*/
mix.js('resources/src/entry-point.js', 'public');
if (Mix.isUsing('hmr')) {
mix.disableNotifications();
} else {
mix.version();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment