In recent years, it’s been a challenge spicing up our Laravel websites and platforms with user interaction via JavaScript. In particular when taking maintainability and scalability into account. In the past we used jQuery and Bootstrap as this was the de facto way of doing it. Later on, frontend frameworks (Vue, React) changed the way we treated frontend assets. With the arrival of Laravel Jetstream (which uses either Livewire or Inertia.js), things have changed once more.
In this post I’ll explain our current approach in detail.
Blade or Vue single file components?
Creating a new Laravel platform with authentication is very easy: just follow the docs and you’ll be up and running in under 15 minutes. However, once you start creating your first routes, controllers and views the question pops up how to handle the frontend assets. With Laravel comes Laravel mix, the package to make compilation of assets easy. If you have a look at the webpack.mix.js file things become clear: you write your JavaScript code in a file resources/js/app.js which is compiled and copied to the public folder. It is this file in /public/js you include in your main layout file. But how do you code this app.js file and make it both maintainable and extendable?
Our approach is to organise our JS code per page. Utilising the relatively new dynamic import feature, we only load the code needed for a specific page. Suppose we wrote some code for the homepage only, for example, a scroll-to-top button. Put this code in a module that exports it as a default function:
This is how we would load this code in app.js
The above example sprinkles a little JavaScript on a page that is generated through a blade template. However, when user interactions become more complex on a page we use Vue to create one or more single file components (SFC). We either use these SFCs as custom html elements in the blade template, or we create a single SFC that takes over the full page and effectively makes the page a SPA within the Laravel site. Below is an example of both approaches.
Vue SFC in blade template
Suppose we have a review page where reviews are shown in a slider that is built with Vue. We would implement this (in app.js) like so:
In the blade template we would need to add <review-slider></review-slider> inside some div with id block_reviews to make it work. The component will only be loaded on the reviews page. We use the excellent vue-slick-carousel package to create the slider, but it’s outside the scope of this post to explain the complete ReviewSlider component.
Vue SPA on a page
Suppose we have another page (e.g., contact) with a lot of user interactions. We decided to make it a SPA inside that specific Laravel page. The blade template is very straightforward, it simply contains a single <div id=”my-spa”></div>. We would arrange this in app.js like so:
Or, with dynamic importing of the component, it looks like this:
The component ContactContainer is mounted to the div#my-app. This means that the div itself is replaced by the template of the component. This component now handles everything on the page, for example
- show contact form and submit (with validation and response feedback)
- show Google map with navigation options
- show helpdesk widget to chat with the company
Summary and conclusion
Working with JavaScript in a Laravel project can be challenging. The project needs to remain maintainable and extendable. In this post I showed several methods to keep your code base clean. Furthermore, the code is dynamically loaded per page which improves the performance of your site. Typically there are three ways to use JS in Laravel:
- import an ES6 module with JS you wrote yourself
- import a Vue SFC and use it in the blade template
- import a Vue SFC and transform the page to a SPA
In the near future we will extend this post with our experiences with the Laravel Jetstream package for scaffolding the frontend.