DEV Community

sustained
sustained

Posted on • Updated on

Laravel Vue Laravel + Vue = ❤️

Something missing or incorrect? This article's source is on Github.

Please feel free to open an issue or send a PR.

Table of Contents

Introduction

Recently the excellent Vue Community guide was released. A guide on all things Vue - written for the Vue community, by the Vue community.

This article's stuture will mirror exactly the layout of the Laravel section of the Vue Community guide, heading for heading.

The intent is to provide a living resource (i.e. it will be updated over time if/when necessary) that goes into far greater detail (including code samples/demos) than the guide (which is intended to be more concise and easier to digest).

Back to top

Reasons to use Vue and Laravel together

Scaffolded by default

A default install of Laravel has everything you need to begin enhancing your server-rendered (Blade) templates with Vue components. No setup necessary.

After having created a Laravel project, you'll be provided with:

  • bootstrap.js:
    • loads some libraries such as lodash, axios and Popper
    • configures axios for CSRF
  • app.js:
    • makes Vue globally available
    • registers the ExampleComponent.vue
    • provides example code on how to automatically register Vue components
    • initialises Vue
  • ExampleComponent.vue:

You are of course free to customise these files to your needs such as by removing unneeded/unwanted libraries.

Back to top

Laravel Mix

Laravel Mix--a fluid API on top of Webpack, also included in the box--takes much of the pain out of asset compiling for you, so you can focus on authoring your Vue components.

You simply need to run npm run watch and then you can get straight to work on writing your Vue components!

It's not quite @vue/cli-levels of awesome but it's actually a really nice library and I do recommend it. It's also not at all tied to Laravel in any way- you can use it in any project.

Back to top

Widespread community adoption

Several prominent members of the Laravel community are proponents of Vue (and its ecosystem).

This includes but is not limited to:

This advocacy and support of Vue, as far as I can tell, extends to the Laravel community as a whole, meaning that a majority of Laravel developers will likely be more comfortable and familiar with Vue than say React or Angular.

Naturally, then, it follows that there will be:

  • more resources to help you learn (guides, tutorials, articles)
  • more people who have experience with Vue+Laravel (help, support, guidance)
  • in general a healthy ecosystem (plugins, boilerplates, etc.)

Back to top

Common gotchas when using Vue and Laravel together

Blade and Vue interpolation syntax

As you may be aware both Blade templates and Vue templates use moustache syntax (i.e. {{ message }}) for variable interpolation, which presents a problem.

Fortunately the solution is simple - just prepend an @ to the moustache statement. This will instruct the Blade template rendering engine to ignore this statement, leaving it to be later processed by Vue.

<p>You have @{{ messageCount }} new message(s).</p>
Enter fullscreen mode Exit fullscreen mode

If you need to escape several moustache statements, you may instead use the @verbatim directive.

@verbatim
    <div class="container">
        <p>Welcome {{ user.name }} ({{ user.id }})!</p>
        <p>Your last visit was: {{ user.lastVisit }}.</p>
    </div>
@endverbatim
Enter fullscreen mode Exit fullscreen mode

Back to top

Passing PHP variables as Vue component props

If you ever need to pass a Blade variable as a prop into a Vue component from within a Blade template then you may be tempted to reach for json_encode however you should instead use the @json directive:

<user-profile :user='@json($user)' />
Enter fullscreen mode Exit fullscreen mode

Back to top

Laravel router and vue-router

You can absolutely use Laravel router and vue-router together without too much effort.

Perhaps you want vue-router to handle all routing; or for it to handle only some and for Laravel to handle the others; or to serve multiple SPAs using one Laravel app. All of this and more is possible.

Setting it all up

NOTE: This section presumes a relatively basic understanding of Vue, vue-router, Laravel and the command line.

The boilerplate provided by Laravel does not include vue-router but it won't be much trouble to set up.

Install vue-router

npm install vue-router --save
Enter fullscreen mode Exit fullscreen mode

Create a router instance and some routes

Create resources/js/router.js:

import Vue from "vue";
import VueRouter from "vue-router";

import PageHome from "./pages/Home";
import PageAbout from "./pages/About";

Vue.use(VueRouter);

const router = new VueRouter({
    mode: "history",
    routes: [
        {
            path: "/",
            component: PageHome
        },
        {
            path: "/about",
            component: PageAbout
        }
    ]
});

export default router;
Enter fullscreen mode Exit fullscreen mode

Create a simple App component

Create resources/js/components/App.vue:

<template>
    <div>
        <nav>
            <ul>
                <li>
                    <router-link to="/">Home</router-link>
                </li>

                <li>
                    <router-link to="/about">About</router-link>
                </li>
            </ul>
        </nav>

        <main>
            <router-view></router-view>
        </main>
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Create a few page components

Create resources/js/pages/Home.vue:

<template>
    <div>Home</div>
</template>
Enter fullscreen mode Exit fullscreen mode

Create resources/js/pages/About.vue:

<template>
    <div>About</div>
</template>
Enter fullscreen mode Exit fullscreen mode

Configure the root Vue instance

Modify resources/js/app.js:

import router from "./router";
import App from "./components/App";

const app = new Vue({
    el: '#app',
    router,               // <-- register router with Vue
    render: (h) => h(App) // <-- render App component
});
Enter fullscreen mode Exit fullscreen mode

Configure the Laravel router

This is the important part - we need to instruct Laravel to route all requests to the index action on the SPAController.

Replace routes/web.php:

<?php
Route::get('/{vue}', 'SPAController@index')->where('vue', '.*');
Enter fullscreen mode Exit fullscreen mode

NOTE: Any routes registered before this catch-all will still function.

This is how we are able to handle some routes with Laravel and others with vue-router.

Create the controller and action

Create app/Http/Controllers/SPAController.php:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SPAController extends Controller
{
    public function index()
    {
        return view("spa");
    }
}
Enter fullscreen mode Exit fullscreen mode

Create the view

Create resources/views/spa.blade.php:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="csrf-token" content="{{ csrf_token() }}" />

        <title>Laravel + Vue = ❤️</title>

        <link href="{{ asset('css/app.css') }}" rel="stylesheet" />
    </head>

    <body>
        <div id="app"></div>

        <script src="{{ asset('js/app.js') }}"></script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

That's it! You are now serving a Vue SPA with Laravel and vue-router is in charge of all routing (except for any routes which were defined before the catch-all, which will be handled by Laravel!).

Back to top

Lack of Webpack aliases when using Laravel Mix

If you've used vue-cli then you'll probably be familiar with (and used to using) aliases such as @ and ~.

Unfortunately this is not setup by default. Fortunately for us - there's a plugin.

Back to top


Thanks and good bye

Thanks for reading and enjoy developing with Laravel and Vue.

Also, be sure to check out the new Vue Community.

Something missing or incorrect? This article's source is on Github.

Please feel free to open an issue or send a PR.

Back to top

Top comments (3)

Collapse
 
sustained profile image
sustained
Collapse
 
sustained profile image
sustained

The PR is now merged.

Collapse
 
renoirtech profile image
Renoir dos Reis

Great job!