Setting up your first Vue.js site using Laravel Elixir and Vueify

Matt Stauffer
9 minute read

It's true what they say—there seems to be a new JavaScript framework every day. We haven't tried them all at Tighten, but we've tried quite a few, and while we've found some lacking, we've found one that truly excels: Vue.js. It's not actually new, but it's started to gain traction recently, and we've found it's a great fit for many of our projects.

Introducing Vue.js

So, what is Vue.js?

It's a JavaScript framework, like React, Ember, and Angular.

It has two-way data binding like Ember and Angular.

It's lightweight and can be used for simple component decoration like Knockout.

It can be pulled into the page with zero complex build steps, but can also easily bundle together its pieces with ES2015 imports.

Its data binding is fast, can utilize computed properties, and comes for free on any data objects passed into it, like React.

It provides tools for separating your code into components, which can be bundled into self-contained files, like in React.

It has a router, so you can use it for Single-Page Apps, but it also works great for single-use components and prototyping.

Its core data structures are simple and work with POJOs (Plain Old JavaScript Objects); your application structure can be as simple or as complex as you want.

To learn more about Vue, check out this post from the creator of the framework: "Vue.js: A (re)introduction" And also check out the free Laracasts series on Vue.

Using Vue on a normal project

Here's how to get Vue working in the simplest use case (without Elixir or Vueify):

(cant' see the fiddle? check it out here)

In this code, we're doing two things: first, we import Vue from a CDN. Second, we create the div (#example) we'll be using as our Vue container and we write out a bit of templating code in it. And third, we create a root instance of Vue and bind it to that container.

As a result, Vue passed the data object to the template that's defined in the view and renders it.

There are a lot of places you can go from here, but we're going to take a huge jump, adding a build system and the Vueify component system. These tools aren't necessary to write Vue, but once your app and components reach a certain level of complexity, you'll find these tools make a big difference in what you can do with Vue.

We're going to switch to Vue's JSX-style component-in-one-file syntax with Vueify, and we're going to use Laravel's Elixir Gulp framework to bring in our dependencies, build our scripts, and give us access to ES2015 syntax with Babel.

Introducing Vueify

Before we dig into how Elixir does that, let's take a look at Vueify. Here's a simple Vueify file, which we'll name Hero.vue:

<template>
  <div class="hero">
    {{ message }}
  </div>
</template>

<script>
export default {
  data () { /* ES2015 equivalent for: `data: function () {` */
    return {
      message: 'Hello World!'
    };
  }
};
</script>

<style>
.hero {
  background: #eee;
  padding: 1em;
}
</style>

That's our component definition. We'd pull it into our primary JavaScript file app.js like this:

import Vue from `vue`
import Hero from `./Hero.vue`

new Vue({
  el: 'body',
  components: { Hero }
});

And we'd use it in the HTML like this:

<!--head, etc., which includes loading the above app.js-->
<hero></hero>

With that, we've placed an instance of our Hero component onto our page.

What is Laravel Elixir?

Let's move onto our build system.

One of the biggest criticisms of React is the complexity of the build tooling you need to understand in order to get working with it. We've covered Webpack before (Unpacking Webpack), but no one's claiming it's particularly easy to learn.

You can use Vue without any complex tooling, but large apps often need more complex systems, which often need more complex tooling.

Gulp and ES2015 imports are the first steps toward making our lives easier. ES2015 imports standardize the process of importing modules between our components. And Gulp is the best build tool I've ever worked with (and yes, I've read that one article or that other one about how NPM build scripts are going to change the world, and I tried them, and I would like to erase the memory of that disaster from my mind for all eternity).

Laravel Elixir is a build tool for the Laravel PHP framework, but it works just fine outside of Laravel. It's a wrapper around Gulp that makes it simple and painless to perform all the development tasks that are most common across the vast majority of web applications.

Take a look at this Gulpfile:

var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    rename = require('gulp-rename'),
    notify = require('gulp-notify'),
    live reload = require('gulp-livereload'),
    lr = require('tiny-lr'),
    server = lr();

gulp.task('sass', function() {
    return gulp.src('resources/assets/sass/app.scss')
        .pipe(sass({
            style: 'compressed',
            source map: true
        }))
        .pipe(autoprefixer('last 2 version', 'i.e. 9', 'iOS 6'))
        .pipe(gulp.dest('public/css'))
        .pipe(rename({suffix: '.min'}))
        .pipe(livereload(server))
        .pipe(notify({
            title: "Karani",
            message: "Styles task complete."
        }));
});

And here's the same file using Elixir:

var elixir = require('laravel-elixir');

elixir(function(mix) {
    mix.sass('app.css');
});

Most importantly, we get Babel (for ES2015) for free, and Vueify for cheap, so we can write simple, distinct components with almost no pain when it comes to putting them together.

So, let's make it happen.

Note: Elixir's dependency list is long, because there's a lot it can do. Once you're a pro Vue developer, you may choose to hand-craft your gulpfile.js and package.json to slim them down. But I'd recommend starting here—and not doing it yourself unless you find a very specific reason to do so.

Using Laravel Elixir and Vueify

First, let's pull Elixir down into our new project.

Importing the packages

mkdir vueify-project
cd vueify-project
touch package.json

Note: If this is a Laravel project, you'll already have Elixir, and you can skip quite a few of these initial steps. The primary adjustment you want to make is to add laravel-elixir-vueify to your package.json and install it, and add a browserify task to your gulpfile.js and point it at your app.js file. Everything else is pretty much the same.

Open up your package.json and fill it with something like this:

{
  "devDependencies": {
    "gulp": "^3.8.8",
    "laravel-elixir": "^4.0.0",
    "laravel-elixir-vueify": "^1.0.0"
  }
}

Where's Vue and Vueify in this list? We're using a custom Elixir plugin called laravel-elixir-vueify, which brings the both in as dependencies.

Now save it, and let's install our packages.

npm install

That's going to take a while, so let's go get our Gulp file started. Create a file in your project root named gulpfile.js and put this in it:

var elixir = require('laravel-elixir');

require('laravel-elixir-vueify');

elixir(function(mix) {
    mix.browserify('app.js');
});

That app.js file is expecting the source to be in resources/assets/js/app.js, and the output to be in public/js/app.js. You can customize that later, but let's just create those files/directories for now:

mkdir -p resources/assets/js
touch resources/assets/js/app.js

And let's run it for the first time (which will create the destination directory for you):

gulp

You'll now have an (almost-entirely) empty app.js file in public/assets/js. That's your file to include in your HTML.

Plugging it into a HTML page

So, let's quickly create a Vue component and stick it into our page. First, let's create public/index.html:

<!DOCTYPE html>
<html>
<body>
    <div id="app"></div>
    <script src="/js/app.js"></script>
</body>
</html>

And let's hook into it in resources/assets/js/app.js:

import Vue from 'vue';

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

Rather than running gulp every time we want to compile our files, let's just open up a new tab or window or pane in our terminal and run gulp watch.

You can now open index.html in your browser and you should see, well, nothing. But we'll get there.

Creating your first component

Let's create a component for our page. We'll start with a user profile.

First, let's create a file named Profile.vue in resources/assets/js. Fill out the component sections:

<template>
  <div class="profile">
    {{ name }}
  </div>
</template>

<script>
export default {
  data () {
    return {
      name: 'Matt Stauffer'
    };
  }
};
</script>

<style>
.profile {
    background: #eee;
    border: 1px solid #aaa;
    border-radius: 2em;
    margin: 2em auto;
    min-height: 150px;
    padding: 2em;
    width: 300px;
}
</style>

Now, let's pull that component into app.js:

import Vue from 'vue';
import Profile from './Profile.vue';

new Vue({
  el: '#app',
  components: { Profile }
});

And finally, let's use the component in index.html:

<!DOCTYPE html>
<html>
<body>
    <div id="app">
        <profile></profile>
    </div>
    <script src="/js/app.js"></script>
</body>
</html>

Save, let gulp run, and then all of a sudden, you have your component on the page:

Profile component name preview

We're not going to cover the entirety of what you can do with Vue here, so if you haven't learned it yet, we'll be covering more topics on how to use Vue here and on my personal blog. But look at what we've been able to do here: with very few lines of code, we have a full ES2015-powered build system with Vueify and it's working right on our page.

Before we're done, let's take a look at how to use import within a component.

Including components in other components

Let's create a quick component for a profile picture. Add a new file at resources/assets/js/Picture.vue:

<template>
  <img class="profile-picture" :src="source">
</template>

<script>
export default {
  data () {
    return {
      source: 'http://loremflickr.com/80/80'
    };
  }
};
</script>

<style>
.profile-picture {
    border: 3px solid #fff;
    border-radius: 50%;
    float: right;
    width: 80px;
}
</style>

Now let's import that into Profile.vue:

<template>
  <div class="profile">
    {{ name }}
    <picture></picture>
  </div>
</template>

<script>
import Picture from './Picture.vue';
export default {
  data () {
    return {
      name: 'Matt Stauffer'
    };
  },
  components: { Picture }
};
</script>

...

And boom. Our profile picture is now showing on the profile.

Profile component with picture

Enjoy! Go forth and vueify.