Laravel chooses Vue but you don’t have to

By Bill Searle — Front-end Developer

I’m in the process of starting a new project here at Mentally Friendly where our de facto back-end framework is Laravel.

Laravel recently adopted Vue.js as their standard front-end JS framework. When you spin up a new install of Laravel you get Vue all setup and ready to go, I think this is pretty cool.
Buuuut… with so many options available as a front-end dev I wanted to see how easy it would be to roll React and Polymer into a new Laravel project.

The approach I’ve taken is to use these component style libraries in conjunction with the Blade templating language in Laravel as this best suits the my use case this time around. 
Case in point, this project will have a large interactive section involving real time chat and other real time updates, outside of that the site will be mostly static. We can also leverage a bunch of built in Laravel features like authentication which we would otherwise lose and likely have to rewrite ourselves if we went 100% JS framework.

Assuming a new install of Laravel v5.3 and a basic understanding of Laravel and Blade views…

Setting up React.js

Install React

cd application
npm install --save react react-dom

Gulp file

  • Configure Webpack
  • Add Webpack to Elixir
// require webpack
require('laravel-elixir-webpack-official');
// configure webpack
Elixir.webpack.mergeConfig({
babel: {
presets: [
'react',
'es2015',
'stage-0',
]
}
})
// add webpack - app.scss and app.js are found here:
// application/resources/assets/sass/app.scss
// application/resources/assets/js/app.js
// This folder structure is a Laravel default
elixir(mix => {
mix.sass('app.scss')
.webpack('app.js');
});

To compile run from /application:

gulp

or for continuous compiling

gulp watch

Rendering React in a Blade template

  • Create your React components in:
application/resources/assets/js/
  • Create layout.blade.php in application/resources/views to contain a @yield('react') directive:
<body>
@yield('content')
@yield('react')
</body>
  • Create a page route in application/routes/web.php and serve a blade view:
Route::get('react', function () {
return view('react-counter');
});
  • Create the blade view containing a div with an id and include the bundled app.js by injecting the script into our 'react' yield area:
@extends('layout')
@section('content')
<div id="counter-app"></div>
@endsection
@section('react')
<script src="/js/app.js"></script>
@endsection
  • Create a React render method in application/resources/assets/js/app.js targeting the div id ie #counter-app:
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from './Counter'
ReactDOM.render(
<Counter />,
document.getElementById('counter')
)
  • Run gulp
  • Visit your route in a browser and you should see your new React component 😎

Caveats

One caveat I have come across with this setup is your components render method will throw an error if it’s target element isn’t available in the DOM. As will be the case if you’re building different components for different pages. To fix this you can either wrap your render methods in an if statement and check that the target element exists or compile each component with Gulp into a separate file and inject them individually.

Setting up Polymer

Install Polymer

cd application/resources
bower init
bower install --save polymer
  • Create layout.blade.php in application/resources/views
<body>
@yield('content')
</body>

Include the components in the <head> of application/resources/views/layout.blade.php:

<script src="../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../bower_components/polymer/polymer.html">

Folders

From /application/resources:

mkdir elements
cd elements
touch elements.html

Include elements.html in the <head> under the previous links:

<link rel="import" href="../elements/elements.html">

Use elements.html to import all your elements from either bower_components or your own custom elements.

Gulp file

Install Vulcanize

cd application
npm install --save-dev vulcanize
  • Require vulcanize
  • copy bower_components into public
  • vulcanize elements.html into public
const elixir = require('laravel-elixir');
const vulcanize = require('gulp-vulcanize');
elixir(mix => {
mix.sass('app.scss')
.copy('resources/bower_components', 'public/bower_components')
});
gulp.task('vulcanize', function () {
return gulp.src('resources/elements/elements.html')
.pipe(vulcanize({
stripComments: true,
inlineCss: true,
inlineScripts: true
}))
.pipe(gulp.dest('public/elements/'));
});

Rendering Polymer in a Blade template

  • Create your Polymer elements in:
application/resources/elements
  • Include your elements in /resources/elements/elements.html:
<link rel="import" href="./polymer-counter.html" />
  • Include the element tag in a blade template:
@extends('layout')
@section('content')
<polymer-counter></polymer-counter>
@endsection
  • Run gulp vulcanize
  • Visit your route in a browser and you should see your new Polymer component 😎

That’s all folks

I was really impressed, surprised actually by how easy it was to get React and Polymer installed with Laravel.

Laravel Elixir really simplified Webpack, if you’ve ever had to set up Webpack it is a pain (and many other four letter words) to get right. And regarding Polymer is was a just a case of dropping in the Vulcanize Gulp snippet (even this isn’t necessary if you’re not using Vulcanize).

As a front-end dev I’m usually drawn to spinning up a Node server and building 100% Angular, React, Polymer or whatever other JS framework/library is flavour of the week!
It was a worthwhile experience integrating them with a back-end framework from scratch, I learnt more about Laravel’s structure and how these JS libraries actually come together through different compiling methods, where they differ, what they depend on and just as importantly, what they don’t. 
Often this is pre-defined is starter kits, great for getting going quickly but not so great for understanding what’s going on in the background.

If you have a different approach, suggestions or anything to say, please leave a comment below.

You can find the Gists here:
React
Polymer

Thanks for reading, cheers 🍻