Creating Your First Vue.js Component for Laravel

  • January 19, 2018

Welcome to the incredibly popular Easy Laravel 5 companion blog. To celebrate the new edition's release (updated for Laravel 5.5!) use the discount code easteregg to receive 20% off the book or book/video package! » Buy the book

This post is an adapted chapter excerpt from the popular book Easy Laravel 5. Easy Laravel 5 provides a comprehensive introduction to the Laravel framework. The latest edition is currently available as a beta release, and can be purchased at a discount price.

Installing Vue.js

Like most popular JavaScript libraries, Vue can be installed in several different ways. However, if you're new to the world of modern JavaScript development, configuring the environment and its typically many dependencies can be an incredibly intimidating task. Fortunately, the Laravel developers have taken care of the vast majority of the installation- and configuration-related issues for you, allowing you to begin experimenting with Vue code almost immediately.

In chapter 2 you learned how about Laravel Mix, which uses Node and npm to create a convenient solution for carrying out otherwise tedious tasks such as CSS and JavaScript compilation. To initialize Mix you need to run the npm install command, which installed the Node packages identified in the package.json file. If you open package.json you'll see the Vue package is included in this list. Therefore if you haven't yet run npm install navigate to your project's home directory and do so now:

$ npm install 

Next you should install the vue-devtools browser extension. Extensions are available for Chrome, Firefox, and Safari, so you'll definitely want to use one of these browsers for Vue-related development. You can install the appropriate extension by heading over to the vue-devtools GitHub page and navigating to your browser's respective extension download link. We'll return to this extension throughout the chapter, so be sure to install it before moving on.

With that done, let's have a look at resources/assets/js/app.js:

require('./bootstrap');

window.Vue = require('vue');

Vue.component('example-component', 
  require('./components/ExampleComponent.vue'));

const app = new Vue({
    el: '#app'
});

This JavaScript file is responsible several key tasks:

  • Loads the bootstrap.js module (also found in resources/assets/js). This file is responsible for loading jQuery, the Bootstrap jQuery plugins, ensuring Laravel's CSRF token is passed as a header when making AJAX requests (more about this later in the chapter), and optionally loading Laravel's Echo API.
  • Loads the Vue module, which we'll obviously need for integrating Vue features into the application.
  • Loads an example Vue component creatively named ExampleComponent.vue. This component is found in the resources/assets/js/components directory. We'll return to this file in a moment, but if you're new to Vue just keep in mind that a Vue component allow you to create reusable HTML widgets which are typically enhanced with dynamic, JavaScript-driven behavior. In this chapter we'll create multiple Vue components while exploring different Vue capabilities.
  • Creates a new Vue instance, and identifies the root element of the Vue application. This root element serves as a cue to Vue that all Vue-related output will be rendered somewhere inside this element. This is often done simply by wrapping everything within your layout <body> with a <div id="app">...</div> element. As you'll soon see we'll rely on precisely this approach.

Let's turn our attention to the aforementioned ExampleComponent.vue file.

Creating Your First Component

Laravel includes a simple Vue component intended to acquaint you with the basic steps required to integrate a component into your application. Although simplistic, it does serve to familiarize you with how a typical component is structured. I'll present the example component's code next, followed by some commentary:

<template>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">Example Component</div>

                    <div class="panel-body">
                        I'm an example component!
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        mounted() {
            console.log('Component mounted.')
        }
    }
</script>

This file is broken into two primary sections. The section encapsulated by the <template> tag defines the widget's HTML. It references various Bootstrap 3 classes, but even if you're not using Bootstrap 3 the HTML will still render once the component is incorporated into your application (albeit not as the Bootstrap 3 developers intend it to). However for the purposes of illustration let's simplify the template to look like this:

<template>
    <div>
        I'm an example component!
    </div>
</template>

The section encapsulated by the <script> tag defines the component's logic. This example uses one of Vue's lifecycle hooks (mounted()) to write a message to the browser console once the component has been rendered to the page DOM. Leave this code untouched for now; we'll modify it plenty in forthcoming examples.

Even novice JavaScript developers are probably wondering how the ExampleComponent.vue file is going to be executed in the browser since it is not valid JavaScript. We're going to use Laravel Mix to compile the Vue code into standard JavaScript! Open a terminal and execute the following command:

$ npm run dev 

This will compile all of the modules and other JavaScript code imported by the app.js file, and save the results to /public/js/app.js. Next we'll want to integrate this file, the designated Vue root element, and the Vue component into our application. In order to most effectively demonstrate this I'm going to recommend creating a new layout and view. Create a new layout named vue.blade.php, placing it in your project's resources/views/layouts directory. It should look like this:

<!DOCTYPE html>
<html>
<head>
<title>Vue Examples</title>
</head>
<body>
    <div id="app">
        @yield("content")
    </div>
    <script src="/js/app.js"></script>
    </body>
</html>

This layout satisfies two key requirements:

  • It defines the Vue root element (#app). Any referenced Vue components must be placed inside this element. We'll reference the example component inside a view which we'll create in just a moment.
  • It references the generated app.js file. It's standard practice is to do so right before the closing </body> tag.

Next, create a new view named vue.blade.php, placing it in your resources/views directory. Add the following to this file:

@extends('layouts.vue')

@section('content')
    <example-component></example-component>
@endsection

That's right, you can reference the Vue component just like an HTML tag! If you return to app.js, notice how we've aliased the ExampleComponent.vue file to the name example-component. The matter of naming in Vue practically warrants a section unto its own, however I'm going to boil the matter down to two crucial rules when it comes to components. First, you should always use compound names when naming components, to prevent conflicts with current and forthcoming HTML elements. This is because HTML elements cannot be named using a compound word. Second, components should always be Pascal-cased (e.g. ExampleComponent.vue as opposed to exampleComponent.vue or examplecomponent.vue) or kebab-cased (e.g. example-component.vue). I'll return to other naming convention tips as warranted throughout the chapter.

Save these changes, and then add the following line to your routes/web.php file:

Route::view('vue', 'vue');

With these pieces in place, open the browser and navigate to your project's /vue URI and you should see output similar to that presented in the following screenshot:

Rendering your first Vue component

Notice in this screenshot I've opened the Chrome development console, and inside it are three noteworthy messages:

  • CSRF token not found: As a safeguard against cross-site forgery attacks, Laravel automatically generates a token for each of your application's user sessions. This token is repeatedly passed between the client and server to confirm the correct user is performing application requests. However, when using AJAX-based requests this token must be passed via the request header. If you return to bootstrap.js you'll see the Axios library (introduced later in this chapter) looks for this token inside an HTML meta tag. You can resolve this error by adding this line inside your application layout's <head> tags:

    <meta name="csrf-token" content="{{ csrf_token() }}">
  • Component mounted: Recall the ExampleComponent.vue file logs this message to the console once the component has been mounted. This is not a requirement, and just serves to demonstrate both Vue's lifecycle hooks and the ability to send messages to the console.
  • You are running Vue in development mode: Your Laravel project's JavaScript build environment is able to determine when your project is running in development mode, allowing Vue to display useful information about error and syntax within the browser's console. Therefore it's a good idea to keep your console open while working on new Vue features.

While you're still in the console, click on the console's Vue tab (presuming you followed my advice and installed the vue-devtools extension). You should see an interface which looks like that presented in the below screenshot:

The vue-devtools browser console tab

This extension can be incredibly useful for debugging Vue components, particularly when you begin nesting them later in the chapter. In this screenshot you can see the ExampleComponent nested under the Root component. Click the ExampleComponent reference and you'll see the message This instance has no reactive state. That will change in the next section.

Want to learn more about Vue.js and Laravel? Buy the book and you'll have access to the entire Vue.js chapter!