- January 21, 2016
Solr + Laravel + Pattern Lab = More Buzzwords!
One of the things I like the most about what we do is the fact that there’s always a bunch of different ways to do the same thing. Chances are, the end result is still just HTML getting rendered by a browser. But the real fun is starting a new project with a little bit of tech freedom that lets you ask yourself: “Wouldn’t it be crazy to try ____?”. Granted, with this team, the answer is almost always “Nah. Go for it!”. But it never hurts to gut check.
A few months back, @markhuot wrote an article about Craft and Pattern Lab. I was the new guy at the time, and wasn’t sure what this Pattern Lab thing was, but I was a little intrigued by a tool that facilitates atomic dev. Combined with Craft, which I love, I was sold pretty quick. If you haven’t read it, I highly recommend you do. In true form, Mark does something a little fun and a lot crazy. The basic gist is, Pattern Lab replaces Twig as Craft’s templating system with a custom PHP Mustache integration. And it works quite well. So well, it inspired me to try the same thing with Laravel.
We recently started working on a project where content is being managed in an enterprise CMS. And, as you might expect, that CMS comes with an equally cumbersome enterprise templating system. Now, before you go and bail on me, I promise I won’t try to convince you that Eclipse is actually fun to use. I have purpose. To make a long story short, none of this sounded awesome, at first. It did, however, get better when we learned Solr was going to be backing our search – as it should.
Let’s talk about data.
With Solr in hand, and content getting indexed neatly into manageable documents for search, our first pass at crazy was to use it as a backend to a traditional Laravel app. Using Solarium we can talk to Solr just as we would any other data source. On top of that, a couple of repository classes give us access to familiar methods to get that data into our templates. After all, our controllers and services don’t really care how $this->articleRepository->getAllArticles();
works. It’s just looking for all of the articles.
Let’s talk about templates.
I’m not going to spend too much time on Pattern Lab. That’s on you this time around: http://patternlab.io/
At its core, Pattern Lab is a custom static site generator that constructs an interface by stitching atoms, molecules, and organisms together to form templates and pages.
Now that we’re Pattern Lab pros, we can make a lot of assumptions about how our front end development is happening. We’ve got mustache files for pages made up of templates made up of organisms, molecules and atoms. On top of that we’ve got a big ‘ol data.json file (or individual json files by page) acting as our mock data source. Fun, right?
Normally, this kind of workflow would be pretty standard. We’d complete front end development in Pattern Lab and then integrate our compiled HTML templates with our app’s templating system and carry on. We’re going to skip an implementation step here by plugging front end development directly into our back-end templating system.
Let’s do this.
When I start a new Laravel app, the first thing I do is ditch Blade in favor of Twig. Nothing personal. It’s just a matter of preference. I’ve been using Rob Crowe’s TwigBridge for this and it’s pretty seamless.
We’re also going to need a PHP Mustache implementation. For this, I’ve been using Bright Machine’s Laratash. Much like TwigBridge, it registers itself with Laravel’s View class, so you can return view(‘my-view’);
all day on any flavor template.
While a majority of our template will be handled by Mustache / Pattern Lab, we’re going to also use Twig to render our chrome without any unnecessary dependencies that make the styleguide work.
First, we’ll create a view namespace that will make it a little easier to render templates directly out of the external Pattern Lab source folder. Laravel makes this really easy for us. In the register()
method of our AppServiceProvider class, we’ll add the following:
# public function register()
{
...
View::addNamespace('PatternLab', ‘/path/to/patternlab/source/patterns/’);
...
}
With this in place, a Laravel controller can return a Pattern Lab template just like any other view:
return view('PatternLab::path.to.pattern');
As-is, this will work. We could render a basic mustache template, print out some variables, iterate arrays, and have access to all of the logic-less templating fun that Mustache provides. What we can’t do is take full advantage of Pattern Lab. Not without telling Mustache how to load partials, and from where.
For our custom loader, we’ll borrow a little from Pattern Lab’s Builder class since they’ve already done most of that hard work for us. Basically, what we’re going to do is map partial names to their pattern files and return their contents on a match. For example, let’s say our “Home” page pattern looked like this:
{{> organisms-header }}
<div class=”content”>
{{> molecules-headline }}
</div>
{{> organisms-footer }}
Without a partial loader, our app has no idea what to do with this, since our pattern directory structure isn’t as literal as native Mustache expects. Now, let’s bridge that gap and help Mustache make sense of Pattern Lab’s directory structure.
To break this down, we’ll override our laratash.partials_loader
config by setting it to our custom partial loader. Keep in mind, you can do this several ways. Typically you would php artisan vendor:publish ___
and add your configs. But for simpler configs and overrides, I find it easier to inject a ConfigServiceProvider class where I can set the little things. Your app, your choice.
config([
'laratash.partials_loader' => App::make('App\Extensions\Mustache\PatternLoader')
]);
Now that we’re all configured, let’s look at how this all works within a controller:
HomeController.php
Remember earlier when I mentioned using Twig to render our chrome? That’s what we’re doing here. Since we don’t want to render pages with Pattern Lab dependencies, extending a custom layout that contains our app’s head and foot gets us over that hurdle. Now, we can return raw HTML to our content block and pass it a php array, just like we would a json array, and we’re off.
home.twig
{% extends “layout" %}
{% block content %}
{{ allOfThePatterns|raw }}
{% endblock %}
layout.twig
<!DOCTYPE html>
<html class="{{ htmlClass }}">
<head>
<title>{{ title }}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="/css/style.css" media="all" />
</head>
<body class="{{ bodyClass }}">
{% block content %}{% endblock %}
</body>
</html>
So, what’s the takeaway?
Staying true to Mark’s article that inspired this approach, we’re not asking too much of any one system. Solr provides our data source, Laravel fetches data and controls routing, and Pattern Lab manages our HTML. All while Json acts as the binding contract in between.
This project is still in the works, but the benefits are already paying out. We managed to expedite development, we tried something new, and we had fun doing it. I call that a win.