Five Vuex plugins for your next project

On the vuejsdevelopers.com blog Anthony Gore suggested a few cool Vuex plugins that could come in handy.
There are a lot of good reasons to use Vuex to manage the state of your Vue.js app. For one, it’s really easy to add super-cool features with a Vuex plugin. Developers in the Vuex community have created a tonne of free plugins for you to use, with many of the features you can imagine, and some you may not have imagined. In this article, I will show you five feature that you can easily add to your next project with a Vuex plugin.
https://vuejsdevelopers.com/2017/09/11/vue-js-vuex-plugins/

Our vue-table-component got some nice improvements

At beginning of the summer we released a new Vue component called vue-table-component. Our aim was to create a very easy to use Vue component to render a table with data. You can toy a little bit with the component on the demo page. Recently Seb and I worked on two cool new features which I want to highlight in this blogpost.

Custom rendering

In the initial version of the component you could simply say which property of the given data should be rendered in which column. Here's a small example:
<table-component
     :data="[
          { id: 1, firstName: 'John' },
          { id: 2, firstName: 'Paul' },
          { id: 3, firstName: 'George' },
          { id: 4, firstName: 'Ringo' },
     ]"
>
     <table-column show="firstName" label="First name"></table-column>
 </table-component>
This will render a simple table with one column (with a header "First Name") and a row for each Beatle. That's nice for simple data but image you want to render something that's not directly in the data. Like for instance a link to an edit page. In the previous version of the component you had to manually prepare that html and put it in the data. Kinda sucky. In the latest version of the component you can use scoped slots to render the data. Here's how to use it.
<table-component
     :data="[
          { id: 1, firstName: 'John' },
          { id: 2, firstName: 'Paul' },
          { id: 3, firstName: 'George' },
          { id: 4, firstName: 'Ringo' },
     ]"
>
     <table-column label="First name">
        <template scope="row">
           <a :href=`/edit${row.id}`>{{ row.firstName }}</a>
        </template>
     </table-column>
</table-component>
Much better!

Asynchronously loading in data

In the previous version of the table component the only way to get data into it was by passing an object in the data prop of table-component. For the project we were working on at the time this was enough. But for the next project we needed to load in data coming from the server so we decided to add support for async loading of data. In addition to accepting objects the data prop of table-component can now handle a function. That function will receive an object with filter, sort and page. You can use these properties of that object to fetch the right data. That function should return an object with a key data that contain the data that should be displayed. If you return a pagination property the component will also render some pagination links. Here's an example where we use Axios, a popular http request library, to get some data from the server:
<template>
   <div id="app">
       <table-component :data="fetchData">
           <table-column show="firstName" label="First name"></table-column>
       </table-component>
   </div>
</template>

<script>
    import axios from 'axios';

    export default {
        methods: {
            async fetchData({ page, filter, sort }) {
                const response = await axios.get('/my-endpoint', { page });

                // An object that has a `data` and an optional `pagination` property
                return response;
            }
        }
    }
</script>

In closing

Our focus with this component is to make it as developer friendly as possible. So it may not have that many features, but it sure is fun to work with. If you want to know more about our component head over to the readme on GitHub. Need a table component, but don't like ours? Here's a good list of alternatives.

Unit testing Vue.js components with the official Vue testing tools and Jest

An official toolset for testing Vue components will be released soon. In a new series Jover Morales tells you all about it.
vue-test-utils, the official VueJS testing library and based on avoriaz, is just around the corner. @EddYerburgh is indeed doing a very good job creating it. It provides all necessary tooling for making easy to write unit test in a VueJS application. Jest, on the other side, is the testing framework developed at Facebook, which makes testing a breeze, with awesome features such as: - Almost no config by default - Very cool interactive mode - Run tests in parallel - Spies, stubs and mocks out of the box - Built in code coverage - Snapshot testing - Module mocking utilities
https://alexjoverm.github.io/series/Unit-Testing-Vue-js-Components-with-the-Official-Vue-Testing-Tools-and-Jest/

Open-sourcing our guidelines

At Spatie we recently launched a new site: guidelines.spatie.be. It contains articles on how we go about setting things up at Spatie and a collection of styleguides. The source code of the site is available on GitHub. In this blogpost I'd like to share why and how we created our guidelines site.

Why did we create this?

Let's start with a quote from Sandi Metz from her excellent post on why we argue about style:
I firmly believe that all of the code that I personally have to examine should come to me in a consistent format. Code is read many more times than it is written, which means that the ultimate cost of code is in its reading. It therefore follows that code should be optimized for readability, which in turn dictates that an application's code should all follow the same style. Adhering to a common style saves you money.
Spatie is web agency. So most of the time we are working on multiple projects at the same time. When the initial project is done, more of than not, we will also maintain it for several years. To keep things manageable we try to code things in a consistent way. That way we can dive into a project and easily reason about it. I'd argue that in addition to adhering to a common code style, setting up your projects in a consistent way will save time and money too. For years I've been the sole developer at Spatie. It was seemingly easy to keep things consistent because there was nobody else working on the code. But the truth is that at the time I certainly did not notice the little differences in my code style across the projects (PSR-2 wasn't a thing back then). Now that the company is growing (Alex recently joined our team with more new members on the way) it's getting more and more important to keep things consistent. Like Sandi mentioned in the above quote code should be optimized for readability. Having all code in a common style will save you money because it takes less time to understand the code. But I'd argue having a style guide will save you time writing code as well. Trying to decide if the view names or route names should be camelCases or kebab-cased? Don't waste your time and just check the relevant guidelines. Most of these rules originate from a discussion of the entire team (or they've been decided by an individual who cared enough to put it in a rule). Having these rules written down avoids discussing them over and over again. Because "best practices" really are nothing more than "current practices" you should still, from time to time, re-evaluate the rules to see if they still make sense.

Behind the screens

The guidelines site itself is build with Laravel. It's completely open source. Here's the repo containing the code that's actually deployed on our server. We've set up the guidelines site in such a way that everybody can contribute it. At the bottom of every page there's an Edit this page on GitHub link. Clicking it will create a PR against the repo. When we merge in the PR the code will automatically get deployed (we use Forge's auto deploy feature for this). Because the guidelines are our very opinionated thoughts on how to do things, we're not going to just accept every single PR we get. You can 't change our minds just by PRing a new rule. But we do welcome new rules that we agree with, or a discussion why our existing rules could be bad. And of course we're also grateful for PRs that fix typos.

Storing the content

The content itself is stored as a set of markdown files. To display every page (expect for the home page), the PageController is used:
namespace App\Http\Controllers;

use App\Markdown\MarkdownConverter;

class PageController extends Controller
{
    public function __invoke($url)
    {
        abort_unless($page = app('navigation')->getPage($url), 404);

        return view('page', [
            'title' => $page->title,
            'editUrl' => $page->edit_url,
            'contents' => MarkdownConverter::convert($page->contents),
        ]);
    }
}

Making content private

The aforementioned PageController controller will ask the Navigation class which page should be displayed. When looking at the code of the Navigation class you'll notice that it also tries to get content from a private directory. This private directory contains content that we don't want to share publicly, such as semi sensitive information and custom procedures that are not interesting for the outside world. The content of that private directory is not in our public repo, but in a separate private repo that's being symlink so Navigation can read it. And of course that private content is only viewable by users who are logged in.

Logging in

At Spatie we use Google Apps and every team member has his or her own email-address on the spatie.be domain. Wouldn't it be nice if anyone with a spatie.be address on Google would be able to login? Then we wouldn't have to create credentials manually whenever we onboard a new team member. That's why we opted leveraging Laravel Socialite to handle logins. Socialite makes it very easy to authenticate with OAuth providers such as Google, Facebook, Github, ... Installing Socialite is very easy. After it is installed and configured the necessary APIs at Google you don't need too much to code to handle social logins. This is the entire LoginController:
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Socialite;

class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function redirectToProvider()
    {
        return Socialite::driver('google')
            ->scopes(['email'])
            ->redirect();
    }

    public function handleProviderCallback()
    {
        $user = Socialite::driver('google')->stateless()->user();

        abort_unless(ends_with($user->getEmail(), '@spatie.be'), 403);

        $authenticatableUser = User::findOrCreate($user);

        auth()->login($authenticatableUser, true);

        return redirect('/');
    }

    public function logout()
    {
        auth()->logout();

        return redirect('/');
    }
}
When visiting /login the app will execute the redirectToProvider method. The user will get redirected to a login page at Google. When users provide the right credentials Google will redirect them back to our site. That response from Google is handled in handleProviderCallback. There we abort unless the email-address of logged in user ends with @spatie.be. And then there's a piece of boring code. Because a socialite user isn't directly authenticatable we find (or create) a regular user in the database and log that one in.

In closing

If you're working in a company that doesn't follow any guidelines to keep code and configuration consistent, I highly recommend talking to your team and convincing them of the value of writing such guidelines down. Take the time to discuss and agree on some common rules. I bet nearly everybody on your team will find such guidelines helpful and it'll make it easy for newcomers to your team. You could opt to just follow our guidelines or create your own set of rules. If you choose the latter, maybe you could use the code of our guidelines site to set up your own. The site and the writing down of the guidelines was largely spearheaded my colleague Sebastian, who, as always, did an excellent job. That site isn't the first thing we've open sourced. Take a look at the opensource pages on our company site to find out the Laravel, PHP and JavaScript packages we previously created.

Use your Laravel named routes in JavaScript

Daniel Coulbourne, an engineer at Tighten Co and co-host of the amazing Twenty Percent Time podcast, recently released Ziggy, a tool to share your Laravel named routes with JavaScript.
Ziggy creates a Blade directive which you can include in your views. This will export a JavaScript object of your application's named routes, keyed by their names (aliases), as well as a global route() helper function which you can use to access your routes in your JavaScript.
https://github.com/tightenco/ziggy

Using global mixins in Vue.js

Recently I needed to add some global functionality to nearly all Vue components in an app. My colleague Seb told me a good way to achieve this: global mixins. In this post I'd like share that knowledge. In Vue a mixin is some functionality bundled in a file that can be added to one or more Vue components. It's very similar to a trait in PHP. Let's take a look at how such a regular mixin looks like. It's really nothing more than a .js with some stuff in it. Here's one with a computed property to grab some global info of the current user that has been set on the window object.
export default {
    computed: {
        currentUser() {
            return window.currentUser;
        },
    },
};
If you import and register the mixin you can use it.
<script>
import Auth from './mixins/Auth';

export default {
   mixins: [ Auth ],

   created() {
      // Let's use the function provided by the mixin.
      console.log(`${this.currentUser.name} is currently logged in.`);
   },
}
</script>
Nice. But image now you want to use the same mixin on almost every component in your app. Registering that mixin will grow old pretty fast. Enter global mixins. It's extremely simple. Just register the mixin where you set up Vue. Commenly this would in app.js:
import Vue from 'vue';
import Auth from './mixins/Auth';

Vue.mixin(Auth); 
And with that you can use the functions defined in the mixin in any component:
<script>
export default {
   created() {
      // No need to import the mixin anymore.
      console.log(`${this.currentUser.name} is currently logged in.`);
   },
}
</script>
We can make a small improvement to this. In the Vue world things that are globally accessible (such as this.$set, this.$root, ...) are commonly prefixed with $. We could follow that convention too: The mixin:
export default {
    computed: {
        $currentUser() {
            return window.currentUser;
        },
    },
};
A component:
<script>
export default {
   created() {
      // so nice
      console.log(`${this.$currentUser.name} is currently logged in.`);
   },
}
</script>
And that's really all there is to it.

What’s in our .babelrc?

Sebastian De Deyne, my colleague and all round wizard at Spatie, wrote a new blogpost on how we use Babel.
A lot has been going in in JavaScript the past few years. One of my favorite things has been the usage of babel, which allows us to write future JavaScript syntax today. The babel ecosystem has tons of plugins and configuration options, I'd like to elaborate on our usage at Spatie.
https://sebastiandedeyne.com/posts/2017/whats-in-our-babelrc

The disadvantages of single page applications

Adam Silver lists a bunch of problems you need to solve if you opt to build a single page application.
Ironically, SPAs are harder to design and harder to build. And yet, they typically produce slow, disagreeable experiences for users. ... Javascript is never going to beat the browser at what it does best—browsing. We can still give users rich and enhanced experiences without cramming an entire site into one document. We should let the browser manage the browsing experience, and spend our time solving real user problems.
https://adamsilver.io/articles/the-disadvantages-of-single-page-applications/

Webpack Academy

Sean Larkin, core team member of Webpack, will be leaving his current job at Mutual of Omaha for a new position at Microsoft. Because on his team he was the one most familiar with the webpack setup of the project, he looked for a way to transfer his knowledge. He landed on creating a video course on webpack that's free for everyone.
I decided to create Webpack Academy, a training and educational platform for those wanting to learn more about webpack. This was a perfect way to not only allow me to give back to my team — by giving them free access to all of the content — but to also benefit the community by sharing it with everyone.
https://webpack.academy/

Exposing Multiple Vue Components as a Plugin

In a new post on his blog Sebastian De Deyne, JavaScript (and all-round) wizard at Spatie, describes a technique to expose Vue components as a plugin.
We recently published a tabs package. Initially, users needed to register two components in order to create a tabular interface: Tabs, which acts as a container, and Tab, which defines a single tab and its contents in the interface. Since developers are most likely going to use both components together, and there's a fair chance that they'd want to register them globally like in the example, it made sense to provide some sort of auto-install option.
https://sebastiandedeyne.com/posts/2017/exposing-multiple-vue-components-as-a-plugin

Building a realtime dashboard powered by Laravel and Vue (2017 edition)

At Spatie we have a tv screen against the wall that displays a dashboard. This dashboard displays the tasks our team should be working on, important events in the near future, which music is playing at our office, and so on. Here's what it looks like: We've opensourced our dashboard, so you can view the entire source code on GitHub. It is built with Laravel 5.4 and Vue. This dashboard is not new, we orginally published it last year. But at our company we like to tinker with new stuff. That's why we did a big refactor of the source code and updated all the dependencies used. The css used got a big update as well, it now uses CSS grid and CSS vars. In this blogpost, which is an update to the previous one, I like to explain how this dashboard is built. You'll need to be familiar with both Laravel and Vue to get the most out of this post. If you need to brush up your Vue knowledge, I can highly recommend Laracast's lessons on Vue.

Video tutorial

Alternatively to reading this blogpost you can watch this talk I did at Laracon EU 2017 where I explain in depth how the dashboard works.

History

We've had a dashboard at Spatie for quite some time now. Before our current Laravel-based one we used Dashing, a framework to quickly build dashboards. The framework was created by the folks at Shopify and uses Ruby under the hood. The time I first built our dashboard, a few years ago, we were at a crossroads at Spatie. There wasn't much momentum in the PHP world and we were toying with the idea of switching over to Ruby. The idea was that by playing with Dashing we would get some experience with the language. Then Composer and Laravel happened and we decided to stick with PHP (and given the current state of PHP ecosystem we don't regret that choice at all). Now that support for Dashing has officially stopped, I thought it was a good time to completely rebuild the dashboard using Laravel and Vue.

High level overview

Let's take a closer look at what the dashboard is displaying. The configured dashboard from the above screenshot has the following tiles:
  • A twitter tile that show all mentions of quotes of @spatie_be
  • A team calendar that pulls in it's events of a Google Calendar.
  • The music that is currently playing in our office, fetched from Last.fm's API.
  • A clock with the current date, and some weather conditions, retrieve from the Yahoo Weather API.
  • The todo's of each member of our team. It's managed through a few markdown files in a private repo on GitHub.
  • Number of package downloads are pulled in via the Packagist API.
  • Same statistics of our numerous public repositories on GitHub
After the browser displays the dashboard for the first time we'll never refresh the page again. WebSockets and Vue are being leveraged to update the tiles. Doing it this way will avoid having to refresh the page and in turn avoid flashing screens. Each tile is it's own Vue component. Laravel's default scheduler is used to periodically fetch some data from the API's of Google Calendar, Last.fm, etc... When Laravel receives a response from any of those services a broadcast event is fired to Pusher. This powerful service leverages websockets to carry over server events to clients in realtime. On the client side we'll use Laravel Echo. That JavaScript library makes handling those Pusher events very easy. Still on the client side each Vue component will listen for incoming events to update the displayed tiles.

The grid

Before diving into the Laravel and Vue code I'd like to explain how the grid system works. The grid system allows you to easily specify where a tile should be positioned on the dashboard and how big it should be. This is the html of the actual blade view that renders the dashboard page.
<dashboard id="dashboard" columns="5" rows="3">
    <twitter :initial-tweets="{{ json_encode($initialTweets) }}" position="a1:a3"></twitter>
    <calendar position="b1:b2"></calendar>
    <music position="c1:d1"></music>
    <uptime position="b3"></uptime>

    <tasks team-member="alex" position="c2"></tasks>
    <tasks team-member="freek" position="d2"></tasks>
    <tasks team-member="seb" position="c3"></tasks>
    <tasks team-member="willem" position="d3"></tasks>

    <time-weather position="e1" date-format="ddd DD/MM"></time-weather>
    <packagist position="e2"></packagist>
    <github position="e3"></github>

    <internet-connection></internet-connection>
</dashboard>
Grid columns are named with a letter and rows are named with a number, like a spreadsheet. The size and positioning of a tile is determined in a position property per component that accepts a column name and a row number. a1 will render the component on the first row in the first column. If you look at the first tasks component you see c2, so as you see in the screenshot of the dashboard, this component will get displayed in the third column on the second row. You can also pass a range to the position attribute. The music component is a good example. Setting grid to c1:d1 causes it to be displayed in the second an third column of the first row. Our dashboard uses five columns and three rows. Want to change the size of your dashboard? No problem: those numbers can be adjusted by passing your prefered number of columns and rows to the columns and rows properties of the dashboard component. Most modern tv's use a 16:9 ratio, but we've gone the extra mile to make the layout fully responsive so it still works on tv's and monitors with a different ratio. My colleague Willem did an awesome job in making the dashboard look very pretty. To position the tiles Willem leveraged CSS grid which was recently introduced in most modern browsers.

The internet connection component

Let's take a deeper look at a component to grasp the general flow. A simple one is the internet-connection tile which notifies us when the internet connection is down. By default is it is not shown. When there's no internet connection a small overlay will be displayed. Here's how that looks: It works by listening to an event, called Heartbeat, that is sent out every minute by the server. When it doesn't get an event within a couple of minutes it'll determine that our internet connection is down (although it could also mean that the server where the dashboard is running on is having problems).

Server side

In the Laravel app you'll see a directory app/Events that containts all events. It also contains subdirectories for each component of the dashboard. All events are sent from the server to the client reside there. In the app/Events directory you'll also see a file named DashboardEvent which is used to transfer data from the server to the client through events.
namespace App\Events;

use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

abstract class DashboardEvent implements ShouldBroadcast
{
    public function broadcastOn()
    {
        return new PrivateChannel('dashboard');
    }
}
That ShouldBroadcast interface is provided by Laravel. All events will get broadcasted on the private channel named dashboard. The client will listen to all events on that channel. Using the PrivateChannel class will ensure that all data will be sent in a secure way so nobody can listen in. More on that later. Let's take a look at the app/Console/Components directory. Almost all logic that the server needs to do to fetch data for the dashboard has a home here. If you open up that directory you'll see that each component has it's own subdirectory. In each subdirectory you'll find an Artisan command that can be scheduled. In our example the App\Components\InternetConnectionStatus class contains this code:

namespace App\Console\Components\InternetConnection; use Illuminate\Console\Command; use App\Events\InternetConnection\Heartbeat; class SendHeartbeat extends Command { protected $signature = 'dashboard:send-heartbeat'; protected $description = 'Send a heartbeat to the internet connection tile'; public function handle() { event(new Heartbeat()); } }
The only thing that this code does is send out a HeartBeat-event. This command is scheduled to run every minute in the Console kernel.

Client side

All JavaScript code used by the dashboard lives in the resources/assets/js directory. In resources/assets/js/app.js you see that the main Vue instance is being initialized on the body element:
new Vue({

    el: '#dashboard',

    components: {
        Dashboard,
        Calendar,
        Github,
        InternetConnection,
        Music,
        Packagist,
        Tasks,
        TimeWeather,
        Twitter,
        Uptime,
    },

    created() {
        broadcaster: 'pusher',
        key: window.dashboard.pusherKey,
        cluster: window.dashboard.pusherCluster,

        this.echo = new Echo(options);
    },
});
The components themselves live in the resources/assets/js/components directory. This is the code of the InternetConnection.vue inside that directory:
<template>
    <section v-if="offline" class="internet-connection">
        <div class="internet-connection__alert">
            <span class="internet-connection__icon h-icon"></span>
            <span class="internet-connection__text">Internet connection</span>
        </div>
    </section>
</template>

<script>
    import echo from '../mixins/echo';
    import { addClassModifiers } from '../helpers';
    import moment from 'moment';

    export default {

        mixins: [echo],

        data() {
            return {
                offline: false,
                lastHeartBeatReceivedAt: moment(),
            };
        },

        created() {
            setInterval(this.determineConnectionStatus, 1000);
        },

        methods: {
            addClassModifiers,

            determineConnectionStatus() {
                const lastHeartBeatReceivedSecondsAgo = moment().diff(this.lastHeartBeatReceivedAt, 'seconds');

                this.offline = lastHeartBeatReceivedSecondsAgo > 125;
            },

            getEventHandlers() {
                return {
                    'InternetConnection.Heartbeat': () => {
                        this.lastHeartBeatReceivedAt = moment();
                    },
                };
            },
        },
    };
</script>
There's a whole lot going on in that code. Let's break it down. Everything between the <template>-tags is the html code that actually gets rendered. That v-if directive makes sure that the section is onlyrendered when the state variable offline is true. Again, if you're having trouble following this, check the series on Vue on Laracasts). In the created method, which is fired as soon as the Vue component is created, we'll make sure that a method on the Vue instance called determineConnectionStatus is fired every second. That function is responsible for determining the value of online. If the last received heartbeat is less than 125 seconds ago, online will be true, otherwise it will be false. Let's review how we can listen for events. In the code above you'll see a method called getEventHandlers. It expects an object of which the property names are the the events names. The event name is the fully qualified class name of the event that get sent out by the server (App\Events\InternetConnection\Heartbeat) but without App\Events and with the \ replaced by a .. So in our example that would become InternetConnection.Heartbeat. The value of the of a property on that object should be a function that will get executed whenever that event comes in from the server. So in our case whenever the InternetConnectionStatus.Heartbeat.HeartBeat event comes in we're going to set the state of lastHeartBeatReceivedAt to the current time. So if this event comes in the determineConnectionStatus function will determine that we're online for the next 125 seconds. Did you notice that the component uses a Echo mixin? A mixin can be compared to a trait in the PHP-world. A mixin contains some functions. Every component that uses the mixin will get those functions. So, like a trait, a mixin is a way to bundle reusable code. The Echo mixin is responsible for adding the power of Laravel Echo to the component. Laravel Echo is a JavaScript library that makes it easy to handle websockets. It will handle all authentication and communication with Pusher. Echo is being set up in app.js Laravel Echo can handle multiple broadcasters, we're going to use Pusher here. That key is a public value that's needed to communicate with Pusher. Let's go back take a look at the code of the Echo mixin.
import { forIn } from 'lodash';

export default {
    created() {
        forIn(this.getEventHandlers(), (handler, eventName) => {
            this.$root.echo
                .private('dashboard')
                .listen(`.App.Events.${eventName}`, response => handler(response));
        });
    },
};
Whenever a component that uses the mixin is created the created function will be executed. It will process the output of getEventHandlers function from the component itself. First, we'll build up the fully qualified event name. Then we'll let Echo listen for events with that name on the private dashboard channel. Whenever an event with the right name comes in we're going to pass the response to the handler and execute it.

The Package statistics component

Let's take a look at another component. In the screenshot of the dashboard you can see that there are some statistics displayed regarding how many times our packages get downloaded. The FetchTotals class, located in app/Console/Components/Packagist/FetchTotals.php is responsible for fetching the package statistics via the Packagist API files on GitHub, and transforming it to an array. After that it'll fire off an event to inform the Vue side of things that new data is available.
namespace App\Console\Components\Packagist;

use GuzzleHttp\Client;
use Illuminate\Console\Command;
use Spatie\Packagist\Packagist;
use App\Events\Packagist\TotalsFetched;

class FetchTotals extends Command
{
    protected $signature = 'dashboard:fetch-packagist-totals';

    protected $description = 'Fetch totals for all our PHP packages';

    public function handle()
    {
        $packagist = new Packagist(new Client());

        $totals = collect($packagist->getPackagesByVendor(config('services.packagist.vendor'))['packageNames'])
                ->map(function ($packageName) use ($packagist) {
                    return $packagist->findPackageByName($packageName)['package'];
                })
                ->pipe(function ($packageProperties) {
                    return [
                        'daily' => $packageProperties->sum('downloads.daily'),
                        'monthly' => $packageProperties->sum('downloads.monthly'),
                        'total' => $packageProperties->sum('downloads.total'),
                    ];
                });

        event(new TotalsFetched($totals));
    }
}

Most of this code should be self-explanatory. It's also scheduled to run periodically. Let's take a look at the TotalsFetched event that's being sent out:
namespace App\Events\Packagist;

use App\Events\DashboardEvent;

class TotalsFetched extends DashboardEvent
{
    public $daily;

    public $monthly;

    public $total;

    public $stars;

    public function __construct($totals)
    {
        foreach ($totals as $sumName => $total) {
            $this->$sumName = $total;
        }
    }
}
When broadcasting events in Laravel, all public properties of an event are being broadcasted as well. So using this code the Vue component can easily get to the values of $daily, $monthly, $total and $stars. Here's the Vue Component that renders the tile on the dashboard:
<template>
    <tile :position="position" modifiers="overflow">
        <section class="statistics">
            <h1>Package Downloads</h1>
            <ul>
                <li class="statistic">
                    <span class="statistic__label">24 hours</span>
                    <span class="statistic__count">{{ formatNumber(daily) }}</span>
                </li>
                <li class="statistic">
                    <span class="statistic__label">30 days</span>
                    <span class="statistic__count">{{ formatNumber(monthly) }}</span>
                </li>
                <li class="statistic">
                    <span class="statistic__label">Total</span>
                    <span class="statistic__count">{{ formatNumber(total) }}</span>
                </li>
            </ul>
        </section>
    </tile>
</template>

<script>
    import { formatNumber } from '../helpers';
    import echo from '../mixins/echo';
    import Tile from './atoms/Tile';
    import saveState from 'vue-save-state';

    export default {

        components: {
            Tile,
        },

        mixins: [echo, saveState],

        props: ['position'],

        data() {
            return {
                daily: 0,
                monthly: 0,
                total: 0,
            };
        },

        methods: {
            formatNumber,

            getEventHandlers() {
                return {
                    'Packagist.TotalsFetched': response => {
                        this.daily = response.daily;
                        this.monthly = response.monthly;
                        this.total = response.total;
                    },
                };
            },

            getSaveStateConfig() {
                return {
                    cacheKey: 'packagist',
                };
            },
        },
    };

</script>
Notice that in the getEventHandlers function we'll update the state variables stars, daily, monthly, total to the values that we get from the TotalsFetched-event.

Security

Because there is some semi-sensitive info being displayed (the tasks of our team members and the events on the calendar) we've added some security to the dashboard. That's why you can't just visit https://dashboard.spatie.be. The url itself is protected by a basic auth filter on the routes. The filter is native to laravel package. Relying on basic auth can be a bit insecure. So if you are going to fork our dashboard be sure to pick a long password and do some rate limiting server side to prevent brute force attacks. The data sent through the websockets is secured as well. In the Echo mixin you might have noticed that a private method is called. This will ensure that, under the hood, a private Pusher channel is used, so nobody can listen in to what is sent via the websockets.

Displaying the dashboard on a TV

Behind our tv there is a Raspberry Pi 2 that displays the dashboard. It is powered by a USB port in the tv and it has a small Wifi dongle to connect to the internet, so cables aren't necessary at all. IMG_0938 (1) The Pi used the default Raspian OS. When it is powered on it'll automatically launch Chromium 56 and display the contents of https://dashboard.spatie.be. IMG_0939 (1)

Reloading the dashboard

For most components, the communication between the server and client is one-way. The client will receive data solely through the events sent out by the server. The client will never make a request for data itself. When our last team member leaves the office he will switch off the wall mounted TV. This will cause the Pi to be powered down as well. The next time when the tv is powered back on the dashboard will be empty, waiting for events sent out by the server. We don't want to stare at an empty dashboard the first hour after the tv is powered on, let's fix that. Every Vue component preserves it's own state in data. Wouldn't it be great to save that data whenever it is changed? Then it could be reloaded whenever the dashboard gets powered on. The SaveState-mixin, which is used on almost every component, does exactly that. The mixin watches the data of the component it's applied to. Whenever data changes, it will serialize the data and write it to local storage. Afterwards, when the component is created, the mixin will restore it's state with the values in local storage. This means that when we power on our tv the saved data will immediately be displayed. We've extracted that mixin to it's own package, so you can use it in your projects: https://github.com/spatie/vue-save-state

Packages used

The dashboard is fetching data from various sources: Google Calendar, Packagist, Lastfm,... Here's the list of packages used to pull in the data:

Alternatives

We mainly built our own custom Dashboard to toy around with Vue and also just because it's fun. There are many alternatives available to display dashboards: Choose a solution that feels good to you.

Closing notes

I hope that you've enjoyed this little tour of the code behind our dashboard. I don't have the intention of creating full documentation for the dashboard and make it monkey-proof as that would require just too much time. On the other hand I do think that if you have some experience with Laravel and Vue it's not that hard to make your own dashboard with our code. The entire source code is available on GitHub. If you have any questions on the dashboard, feel free to open up an issue on the issue tracker.

What to expect from JavaScript ES2017

In a new blogpost André Neves, a React Native engineer at Big Human, introduces the new features that are coming with ES2017.
I think it is a fair assessment to say that a large portion of JavaScript developers seem to appreciate the new, the shiny, the bleeding-edge tools. Whether it is to completely embrace a new technology, or simply to test out a tool's functionality, we like to know what is out there to at least 'dip our toes in the water'. If you're like me, keen on knowing about all of the new technology this incredible community has to offer, here is a breakdown of what ES2017 has in store.
https://medium.com/komenco/what-to-expect-from-javascript-es2017-the-async-edition-618e28819711

A straightforward Vue component to filter and sort tables

Today we released our newest Vue component called vue-table-component. It aims to be a very easy to use component to make tables filterable and sortable. In this post I'd like to tell you all about it.

Why creating yet another table component?

Let's first touch upon why we created it. To make lists of models sortable and filterable we used to rely on the venerable DataTables.net component. It works great, but comes with a few caveats. First, it's built on jQuery. In our projects we avoid using jQuery nowadays and use Vue specific components. Secondly, there's a lot of stuff in there that we don't need, we probably are only using 10% of it's features. So for our use cases, it's a bit bloated. And lastly, because it contains so much features, using it can be a little unwieldy. When creating our own table component we had only our specific use case in mind: a small set of data that is passed via json.

Using vue-table-component

Here's an example of how you can use the component:
<table-component
     :data="[
     { firstName: 'John', lastName: 'Lennon', instrument: 'Guitar', editUrl: '<a href='#john'>Edit</a>', birthday: '04/10/1940', songs: 72 },
     { firstName: 'Paul', lastName: 'McCartney', instrument: 'Bass', editUrl: '<a href='#paul'>Edit</a>', birthday: '18/06/1942', songs: 70 },
     { firstName: 'George', lastName: 'Harrison', instrument: 'Guitar', editUrl: '<a href='#george'>Edit</a>', birthday: '25/02/1943', songs: 22 },
     { firstName: 'Ringo', lastName: 'Starr', instrument: 'Drums', editUrl: '<a href='#ringo'>Edit</a>', birthday: '07/07/1940', songs: 2 },
     ]"
     sort-by="songs"
     sort-order="asc"
     >
     <table-column show="firstName" label="First name"></table-column>
     <table-column show="lastName" label="Last name"></table-column>
     <table-column show="instrument" label="Instrument"></table-column>
     <table-column show="songs" label="Songs" data-type="numeric"></table-column>
     <table-column show="birthday" label="Birthday" data-type="date:DD/MM/YYYY"></table-column>
     <table-column show="editUrl" label="" :sortable="false" :filterable="false"></table-column>
 </table-component>
Let's take a look on how our component will render that piece of html. The component doesn't come with any styling, so you'll need to provide your own css. Head over to the demo page to play with the rendered output. You've probably noticed that a filter field is added to the top. By default all data will be used in to filter. If any columns contain html it will be filtered out before filtering. So even though that last column contains links, filtering on href won't yield any results. If you don't want a column of data to be filterable just add :filterable="false to table-column. Like expected, clicking a column header will sort the data. If the data contains a column with numerical values or dates you must set a data-type prop on table-column. Don't want a column to be sortable? No problem! Just pass a sortable property set to false to table-column. The component will also remember it's state for 15 minutes. So when you reload the page that filter and sorting you used previously will still be used. Head over to the readme on GitHub to learn all the props that can be passed.

In closing

Like mentioned before our table component is very much targeted to our use case. Our intent is to keep this component very clean and simple. If you need more features, take a look at the numerous other Vue components out there that can render table data. Because in our client projects we are using Vue more and more you can expect some more opensource Vue components from us soon. If you haven't already done so, be sure to take a look at this list of things we opensourced previously.

Classes, complexity, and functional programming

In this article Kent C. Dodds clearly explains what the downsides are of using Class in JavaScript.
Classes (and prototypes) have their place in JavaScript. But they’re an optimization. They don’t make your code simpler, they make it more complex. It’s better to narrow your focus on things that are not only simple to learn but simple to understand: functions and objects.
https://medium.com/@kentcdodds/classes-complexity-and-functional-programming-a8dd86903747

TypeScript With Laravel Mix

In a new post on his blog Sebastian De Deyne, multi disciplinary wizard at Spatie, explains how to set up TypeScript in a typical Laravel app.
In a recent Spatie project we decided to give TypeScript a shot for the business critical part of a new application. TypeScript provides static analysis to reduce the chance of introducing bugs, to have self-documenting code, and to improve our tooling (autocompletion!) Adding TypeScript support is pretty straight forward and is done in three steps: install the necessary dependencies, configure TypeScript, and finally configure Laravel Mix.
https://sebastiandedeyne.com/posts/2017/typescript-with-laravel-mix

Testing a Vue component part 4: more testing and faking time

Welcome to part 4 of a series on how to test a Vue component. Here's the table of contents of the series:
  1. Starting out with tests
  2. The first test and snapshot testing
  3. Creating an instance of a component
  4. More tests and faking time (you're here)
  5. Jest awesomeness and a skeleton to get started More tests and faking time

More tests

If you navigate to http://vue-tabs-component.spatie.be/#second-tab you'll notice that the tab named Second tab is automatically opened. Let's take a look at the test that makes sure this functionality works.
it('uses the fragment of the url to determine which tab to open', async () => {
    window.location.hash = '#second-tab';

    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});
Let's go through it in detail. First we set the hash of the current window.location (that's JavaScript speak for the current url) to #second-tab. Remember, Jest comes with jsdom out of the box. It's jsdom that provides us with that window instance. Next we create a new Vue instance and await until Vue has done it's thing. Finally we assert that the rendered output matches the saved snapshot. Of course I've manually verified, when that snapshot was first created, that it's content was correct.

Asserting against a component property

Instead of using snapshots to make assertion you can also just assert against a property in the state of a Vue component. Let's see how that works. Our vue-tabs-component has a neat feature where you can make a tab use a custom fragment. Here's the relevant test.
it('uses a custom fragment', async () => {
    document.body.innerHTML = `
        <div id="app">
            <tabs cache-lifetime="10">
                <tab id="my-fragment" name="First tab" >
                    First tab content
                </tab>
            </tabs>
        </div>
    `;

    const tabs = await createVm();

    expect(tabs.activeTabHash).toEqual('#my-fragment');
});
First we set up some html and we await until Vue has done it's thing. Like mentioned before the createVm method return an instance of the Tabs component. We implemented our component in such a way that the activeTabHash-property in it' state always contains the hash of the tab that's being displayed. In that last line of the test we simply assert that the property contains the expected value.

Faking time

By default our tabs component will remember which was the last open tab. If you for instance navigate to http://vue-tabs-component.spatie.be/#second-tab and then to the same url without the fragment you'll notice that the Second tab is being displayed. The component remembers, for a limited amount of time, the last opened tab by writing the hash of the selected tab to local storage. Here's the code that does that:
expiringStorage.set(this.storageKey, selectedTab.hash, this.cacheLifetime);
That expiringStorage class is something custom that is included in the project. It's a wrapper around local storage. It makes items in local storage expiring. expiringStorage has it's own tests. Let's take a look one of those tests.
it('remembers values by key', async () => {
    expiringStorage.set('my-key', 'my-value', 5);

    expect(expiringStorage.get('my-key')).toEqual('my-value');
});
Pretty simple right? We store my-value in the storage using the key my-key and then we assert that we get the same value when getting my-key. That last parameter is the lifetime in minutes. Of course we should not only test that the value is being saved, but that is expires after five minutes. Here's the test for that:
it('returns null if the value has expired ', () => {
    expiringStorage.set('my-key', 'my-value', 5);

    progressTime(5);

    expect(expiringStorage.get('my-key')).toEqual('my-value');

    progressTime(1);

    expect(expiringStorage.get('my-key')).toBeNull();
});
We assert that after exactly 5 minutes we still get the right value. If time progresses any further the value is forgotten and null is returned. That progressTime() function is not part of Jest. It's coded up in the tests themselves. Let's go take a look at it's implementation.
function progressTime(minutes) {

    const currentTime = (new Date()).getTime();

    const newTime = new Date(currentTime + (minutes * 60000));

    const originalDateClass = Date;

    Date = function (dateString) {
        return new originalDateClass(dateString || newTime.toISOString());
    };
}
We'll go over this line by line. In JavaScript a way of getting the time is the built-in Date class.
const currentTime = (new Date()).getTime();
We calculate the new time by adding the right amount of milliseconds to it.
const newTime = new Date(currentTime + (minutes * 60000));
Here comes the tricky part. We here going to hold a reference to the original date class. And then we are going to replace the built-in Date with our own function.
const originalDateClass = Date;

Date = function (dateString) {
    return new originalDateClass(dateString || newTime.toISOString());
};
This is called monkey patching. The original Date is replace by a function that, given no parameters, it won't return the actual time, but the time we gave it (newTime). Cool! Btw you can't do it this in PHP, which is a shame because it would make testing stuff a lot easier. Now that you understand how progressTime works let take a look at these two tests from inside tabs.test.js.
it('opens up the tabname found in storage', async () => {
    expiringStorage.set('vue-tabs-component.cache.blank', '#third-tab', 5);

    const tabs = await createVm();

    expect(tabs.activeTabHash).toEqual('#third-tab');
});

it('will not use the tab in storage if it has expired', async () => {
    expiringStorage.set('vue-tabs-component.cache.blank', '#third-tab', 5);

    progressTime(6);

    const tabs = await createVm();

    expect(tabs.activeTabHash).toEqual('#first-tab');
});
In the first test we set a value in the expiring storage with a key we know our component will use. Then we let Vue do it's thing. When it's ready we assert that the right tab is active. In the second test we set the same value in the expiring storage, but then we are going to progress time. Finally we assert that the item in expiringStorage is not being used, but that the first tab is being used. Now you might think that the that last test is a bit unnecessary. To so degree you're right: with the test of the expiringStorage class itself we already covered the items do in fact expire. But that extra extra component test gives me some extra confidence that the component behaves correctly.
You've reached the end of part four. Only one more part to go: Jest awesomeness and skeleton to get started

Testing a Vue component part 3: Creating an instance

Welcome to part 3 of a series on how to test a Vue component. Here's the table of contents of the series:
  1. Starting out with tests
  2. The first test and snapshot testing
  3. Creating an instance of a component (you're here)
  4. More tests and faking time
  5. Jest awesomeness and a skeleton to get started

Creating an instance of the Vue component

Now you know what snapshot testing is, let's take a fresh look at that first test:
it('can mount tabs', async () => {
    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});
The component itself is created in the createVm() function. We'll explain that await thingie a bit later. Let's take a look at createVm first. You can find it's implementation at the end of the file.
async function createVm() {
    const vm = new Vue({
        el: '#app',
    });

    await Vue.nextTick();

    return vm.$children[0];
}
Here we actually create a Vue instance. It will operate on the #app node. Remember we set the dom to some html earlier in the test. Vue will go do it's business and replace tabs and tab tags by the templates inside the Tabs and Tab components. It will not do this immediately but in an asynchronous way. We need to wait until Vue is ready. That's what that Vue.nextTick() line is all about. This will resolve after Vue's done with it's rendering work and all it's magic. If you read the documentation regarding nextTick you'll learn it returns a promise when you don't pass it any parameters. So you can use then() on it. If you're not familiar with promises, read this article about them.
Vue.nextTick().then(function() {
  //do stuff when Vue is ready
});
The problem if we were to use it that way is that only inside the callback we would know that Vue has done it's job. Luckily there is a new JavaScript feature that we can make use of: async/await. In short it lets you write asynchronous code in a synchronous way. Instead of having to pass a function to then when can put the await keyword before Vue.nextTick(). The code underneath that line will only execute when Vue.nextTick() is done.
await Vue.nextTick();

//do stuff when Vue is ready
Cool, so now we lose one level of indentation. You might think: "Freek, this is madness, now the code is blocking". But rest assured that behind the curtains JavaScript will still use promises and run asynchronously. Async/await is just syntactic sugar. You should also know that any function that uses await should be marked as async. That's why you see async appear in createVm()s function declaration. If you want to know more about async/await read this article on PonyFoo or this one on Hackernoon. This is the last line of the createVm function:
return vm.$children[0];
This line returns the first child of the Vue instance, which is the initialized Tabs component.

Back to the first test

Let's take a a third and final look at the our first test.
it('can mount tabs', async () => {
    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});
Now you should understand more or less everything that is going on. First we create a new Vue instance that will operate on the dom we set in the beforeEach each method. With that await keyword we will wait (in an asynchronous way) until Vue has done it's business. And finally we assert that the html matches the content of the snapshot. Congratulations for reading until here. I hope you learned a lot by diving into that first test. I promise that with this new knowledge the rest of the test are now easier to understand.
Understanding that first test was hard, but now you've taken that hurdle, grasping the next tests will be easier. If you're eager to know more head over to the fourth part of this series: More tests and faking time.

Testing a Vue component part 2: the first test and snapshots

Welcome to part 2 of a series on how to test a Vue component. Here's the table of contents of the series:
  1. Starting out with tests
  2. The first test and snapshot testing (you're here)
  3. Creating an instance of a component
  4. More tests and faking time
  5. Jest awesomeness and a skeleton to get started

Setting up the world

Let's take a further look at tabs.test.js. Near the top of the file you can see this line
beforeEach(() => {
The function that is passed to beforeEach will be run before each test. It's used to set up the 'world' you're testing in. It's equivalent to setUp method of PHPUnit if you're familiar with that. Let's take a look what's inside beforeEach. That first thing that's happening there is this:
document.body.innerHTML = `
    <div id="app">
        <tabs>
            <tab name="First tab">
                First tab content
            </tab>
            <tab name="Second tab">
                Second tab content
            </tab>
            <tab name="Third tab">
                Third tab content
            </tab>
        </tabs>
    </div>
`;
Here we see one of Jest's cool features. It comes with jsdom built in. Jsdom simulates an entire DOM as if you were in a browser. In that code snippet before we're making sure that each test starts out with that piece of html in the dom.

The first test

Before reviewing the rest of beforeEach, let's take a look at the very first test. The purpose of this test is to assert that when the component is mounted the right html is being used. "Mounted" is Vue speak for "when the component has fully started up and has been rendered".
it('can mount tabs', async () => {
    await createVm();

    expect(document.body.innerHTML).toMatchSnapshot();
});
Even though it's just a few lines there are a lot of things going on, and I can imagine it's a bit confusing if you're not familiar with modern Javascript. Let's go through it in detail. What happens here is that we first are creating an instance of our component (more on that later) and then assert that the html being displayed, so the value of document.body.innerHTML, is correct. That expect method is part of Jest itself. Jest contains various methods to assert things such as toEqual, toBeNull and much more. On this page in the Jest documentation you can see all available assertion methods. Instead of asserting the contents of document.body.innerHTML against a big piece of html, we use toMatchSnapshot here. Let's find out what that method does.

Snapshot testing

The basic idea of snapshot testing is that you compare the output of your code against a file that's written on disk. That file is called a snapshot. If the output of your test matches up with the contents of that snapshot, it succeeds, otherwise, it fails. It's as simple as that. In our project the test are stored in the __tests__/__snapshots__ directory. If you open up tabs.test.js.snap you'll see the html that is used in the can mount tabs tests. The cool thing is that you don't need to write those snapshots by hand. Jest can generate them for us. If you delete tabs.test.js.snap file and run the test again you might think that the can mount tabs will fail, but you're wrong. Let's see what happens. You can run the test separetly with this command
jest -t="can mount tabs"
You can see in the output of the command that there was one snapshot generated. The tabs.test.js.snap has been created. You could now verify in that snapshot if the content is equal to the output you were expecting. Run the test again and you'll see that it'll pass. Let's try and make the test fail. We're going to cheat a little here and mimick changed output by just editing the current snapshot (in real life you would never edit the snapshot manually). If I changed the html in the snapshot a bit and run the test again, it fails. If you want to know more about snapshot testing you can read this article my colleague Seb wrote about it, watch this video on how I used snapshot testing in PHP or just go over the relevant page in the Jest documentation.
We've learned some good things about that first test. But there's more. The story continues in part 3 of the series: Creating an instance of a component