Originally posted on Medium/@Buildit
As we have learned from previous instalments, various other sources online and our work with our clients, a Design System can mean many things and what it is in practical terms really boils down to what you’re trying to achieve.
Of the many tools available now, PatternLab is one that would provide a good flexible infrastructure and solves a lot of the problems related to the fuzzy definition of a Design System.
I’ve decided to put this to the test and see what can I achieve with it, by leveraging on its internal modularity system, and in the process, trying to eliminate a lot of the initial setup work that is usually needed.
Before we move on, let’s have a quick look at what is PatternLab allowing us to do.
TL;DR: PatternLab modularity system
Since Version 2, PatternLab has improved massively from a user standpoint, being one of the first tools to help us create a pattern library, and over time the community behind it grew enough to be able to provide enough feedback and use cases.
PatternLab now provides what it’s called the Edition, which is a layered approach to the development of whatever you want to do with it: the Core, the PatternEngine (the templating engine used for the templates), the StyleguideKit (essentially the UI theme for PatternLab itself), and the StarterKit.
Pattern Lab Edition diagram
I’ve decided to focus my attention on the StarterKits and how to make the most out of them, and will cover the following topics:
- Understanding StarterKits,
- Dependencies and requirements,
- Validating the development workflow.
DISCLAIMER: Before we start, keep in mind that this whole article gravitates around the Node version of PatternLab. Even then, it should be quite straightforward to port the most of it over to the PHP version, but I haven’t been using it for quite a while now, so I don’t know what’s the amount of effort required.
As we saw above, StarterKits provide the highest level of abstraction over PatternLab and separate quite nicely the majority of the data you would normally have to deal with on a daily basis within it.
StarterKits are what the name suggests: starter kits. To put it in other words, it provides some sort of scaffolding for some if not all the files that live inside the source/ folder. There are some already-made examples you can start from and have a look how they’re organised. If you’ve used PatternLab before, you should be quite familiar with the starterkit-mustache-demo that contains all the templates and files that are used for the demo website of PatternLab.
PatternLab provides a post-install script that will try to detect any starterkits you have installed via npm. This script is responsible for copying anything that sits under the starterkit dist/ folder over to the source/ folder in PatternLab.
Since we like to have npm packages namespaced, I’ve found that the post-install script won’t work as expected (since it looks for packages starting with starterkit-*) so my best option is to use the CLI command manually, as such:
You will notice from the output of the command that the content of source/ is getting overwritten. I will come back to this later on.
Ideally, this process should be done only once, as it means that any configuration or improvement done from that will be overwritten and your efforts lost (well, unless you’ve committed your stuff, of course)!
Dependencies and requirements
As usual, with most projects, understanding the main problem and the possible solution(s) is the first and most important step to tackle.
The basic idea I want to achieve is the following:
- Move all the design system related code into one or more StarterKits,
- Make sure that PatternLab will work smoothly with them.
The first part is about understanding how to architecture the StarterKits, while the second part is about enhancing PatternLab with the right tools so that little is left to the developer to deal with, allowing for concentration on the important stuff.
Once we cover all the basic technical aspects, I will dig into the workflow and what that means in practical terms.
Making StarterKits useful
For the purpose of what I’m doing, I’ve decided to leave only templates (Mustache files in my case) in the StarterKits. In my case I will go with at least 3 different StarterKits, very much based on the following architecture:
The structure of a Design System, broken down into Building Blocks, UI Patterns, and Rules — credit goes to UXPin
This structure is inspired by a UXPin article, and these could be just the first few I’m building: I want to be able to have different StarterKits that I can mix and match according to what I need to build.
The question that came out as soon as I decided to move into this code organisation is where the whole CSS dependencies should live and how they should be tied together.
In web projects, this is quite important since you might need to create a SASS/CSS library as you go along and build your design system, especially when it comes to the UI Patterns section.
It’s also very important to understand the different CSS layers that are used by PatternLab:
- /source/styleguide/css/: here lives everything that is usually styling the actual chrome UI of PatternLab (e.g. what would be provided by a StyleGuideKit I mentioned above)
- /source/css/pattern-scaffolding.css: this contains all the styles that are used to display the patterns within PatternLab. These styles are the UI Components (if you want) for PatternLab. A very classical example are swatches for colour palettes.
- /source/css/style.css: this is the actual stylesheet for your own pattern library, that is, what you would normally use on a daily basis in your own project. This shouldn’t contain anything that is used specifically in PatternLab.
The simplest solution is to keep all these stylesheets within the core PatternLab project, and that probably should work fine in most instances.
I’ve instead decided to take it a step further and see if I could decouple these dependencies and provide another layer of abstraction for a better composition of the various StarterKits.
After a lot of tinkering around, the final architecture solution I decided to create is the following:
The final architecture organisation of PatternLab in conjunction with 3 different StarterKits
As you can see, each StarterKit would bring along their own scaffolding CSS, while the “foundation” library (not to be confused with the Zurb Foundation Lib) is composed of basic styles that would be universally available across all the StarterKits. The UI Patterns StarterKit instead would benefit from a more extensible SASS library on top of that. This separation will also provide a clean way to create and export your own SASS library for public distribution and consumption.
How to make PatternLab truly interoperable
PatternLab is fundamentally barebones when it comes to features and automation, for a good reason, as it is its intended scope.
Here are the few changes I had to make in order to achieve what I wanted:
- Introduce SASS compilation (I’m using Gulp for this),
- Introduce aggregation of all the scaffolding files, to avoid collisions,
- Add style linting (because why not?),
- Clean up a bunch of files that are not needed when using StarterKits.
Before we even get into any of this, be sure to grab a copy of gulpfile.js that is available from the edition-node-gulp. Gulp should already be in the dependencies, so be sure to run the npm install before you move on.
Adding SASS compilation
For the SASS compilation there are some instructions available somewhere (probably not particularly up-to-date) and the solution I’m going to present here is very much based on that, and it’s also the simplest I could achieve without having to rewrite half of the gulpfile.js, so I’m sure something better can be achieved.
Let’s add gulp-sass to our dependencies:
$ npm install -s gulp-sass
If you’re using npm v5+ you don’t need the -s option as it would save it automatically.
At the top of the file, we then need to require the lib, as per usual, in order to use it:
Now the current implementation of the gulpfile.js is just copying /source/css/style.css into /public/css/ using the task pl-copy:css. I won’t be touching this task, and instead add a task pl-sass for compiling the SASS files that would be residing into /source/sass/ with style.scssbeing the entry point, which means we would then need to remove the style.css file from Git:
Add the SASS files to the list of watched files:
And then add it to the compilation steps in pl-assets:
In the task, we are also adding a call to done() using a callback function to notify the end of the process in case anything is needed to be triggered afterwards (e.g. browser reload) and to handle errors.
We are left with the removal of the compiled CSS file from Git so that every change won’t bother us into committing anything:
And then the actual removal of the file:
$ git rm –cached source/css/style.css
Don’t forget to commit the changes after this:
$ git add source/css/style.css
$ git commit “removed style.css from tracking”
Avoiding pattern scaffolding clashes
The core idea of pattern scaffolding in the scenario I’ve envisioned here is that you can create the styles used specifically by each set of templates. The problem with this approach is that there’s no immediate way of making it work out of the box, so some further tweaking of the gulpfile.js will be required.
For this we would need to set some basic rules since we won’t be touching the way files are copied over from the StarterKit: each file will have to be named differently, a simple numbered prefix could suffice, as long as pattern-scaffolding is still present in the name. For instance, I have:
- 00-pattern-scaffolding-rules.csscoming from the Rules StarterKit,
- 01-pattern-scaffolding-base.csscoming from the Building Blocks StarterKit,
- 02-pattern-scaffolding-components.cssfrom the UI Components StarterKit.
All these files will be concatenated in the expected pattern-scaffolding.css file that PatternLab is expecting.
For this to work we would then use gulp-concat for concatenating all the files together:
$ npm install -s gulp-concat
Now, back on the gulpfile.js:
const concat = require(‘gulp-concat’);
And the task will be something along the lines of:
As you can see, I’ve modified the original pl-copy:css and renamed into pl-copy:css:style to target style.css specifically, otherwise it would grab everything in the directory.
Lastly, let’s add the tasks to the build process:
and update the watcher so they’ll be triggered during the update:
As before, we can remove the pattern-scaffolding.css file from Git.
SASS libraries and last few bits
I won’t be digging too much into the technical details of this, but for the sake of completeness it’s important to remember that the SASS libraries, the foundation and the UI components one, would live outside of the repository as external npm dependencies.
The foundation library would provide the basic styles (you can think of them as Atoms, from an Atomic Design point of view), which would make them easy to apply across all the different StarterKits without too many efforts.
The UI Components library is instead a specific requirement of the UI Patterns StarterKit, which contains all the modules we would need to build any application.
This approach would grant us maximum reusability and composability, especially if we think that the whole purpose of this work is to allow us to create Design Systems that would be almost ready to be used by our clients or projects with the minimum amount of effort.
For this same reason, I’ve also decided to use Eyeglass, a simple npm module that helps load SASS dependencies without having to specify their full path in the gulpfile.js or in the @import statement in your SASS files. On the other hand, it won’t be exposing the SASS files into PatternLab, but I think this is a trade-off that would be perfect as it almost simulates a real-case scenario.
The result is that in the main PatternLab SASS file, /source/sass/style.scss will contain essentially only the following:
Validating the workflow and final notes
At this point, you may ask yourself if this whole thing is actually sustainable and works as expected, so I think it’s worth taking the whole system for a spin and showing how the development and maintenance cycle is supposed to work.
Developing the system
In order to get to a usable situation, there’s some work that needs to be done, which isn’t much if you (now) know how to achieve it. This translates in the following tasks:
- cleanup of PatternLab (i.e. core + engine + StyleguideKit),
- development of the initial state of the StarterKits (2+, depending on the complexity of the applications you need),
- development of the foundation and UI components libraries.
As I was highlighting at the beginning, if you have a pretty good idea of what you’re trying to achieve, what kind of Design System you or your clients need, and how it’s going to be organised, this step might be quite straightforward.
The “hardcore” development part is around the SASS libraries, which is also very much optional, or might require just some adjustments over something you have already built previously.
While developing the various StarterKits, I’ve found that the whole process of copying the files over to the main PatternLab every time the content has changed can be quite annoying, as it’s not a process that can be automated through Gulp. This is normally not needed, but could be useful to see the final result or to adjust some of the pattern scaffolding styles.
The good thing is that while working locally, using npm link saved quite a lot of time (and it’s also suggested in the PatternLab Docs), which means that the files available in node_modules are always up-to-date.
I’ve also found that after the StarterKit file copy, the CSS files needed to be rebuilt every time, probably due to the fact that they are an external dependency. I haven’t got to that part yet, and I’m assuming it’s just a question of modifying one of the tasks and triggering the compilation when the files are being updated.
Developing the actual Design System
The boring part is now done, and presumably you’re only left with the development of the actual Design System. This would mean that the initial project can be kick-started by copying over the StarterKits and committing all the changes. The whole development now will gravitate around the following:
- Improving the documentation supporting your Design System (if you need that),
- Developing the actual UI Patterns,
- Developing the SASS UI library.
This is very much in line with what you would have before, with the added benefit that most of what you need to start from is already there, and you only need to get to work on the juicy bits.