- December 1, 2016
A Webpack Pattern Library
I am very excited for the upcoming adoption of web components. They provide a number of improvements to the developer experience of managing large codebases. If you’re not up to speed there’s a good article over on CSS-Tricks covering all the basics. It’s a bit dated but the core concepts haven’t changed too much.
When web components finally do land the power is going to be in the import
element and the ability to bring outside code into your page in a controlled manner. So, if you want to display a tabset you could <link rel="import" href="tabset.html">
and interact with that tabset through an exposed API such as,
<tabset> <tab> <tab-heading>Tab 1</tab-heading> <p>This is my tab content!</p> </tab> <tab> <tab-heading>Tab 2</tab-heading> <p>This is my tab content!</p> </tab> </tabset>
With the above you’ll get all the HTML, CSS, and Javascript necessary to turn our short markup into a fully functional, accessible, and styled tabset without ever having to worry about the underlying structure.
However, here in the real world we’re stuck with the browsers of the day for a few more years. But that doesn’t mean we can’t prepare ourselves for the upcoming web component craze. With that in mind I’ve been working with Webpack to abstract out my components into reusable chunks.
The goal of my experimentation was to create a system that provided the same level of importability as web components. That way I could work with a tabset on its own and include it into whichever templates I needed to place it.
Note: web components also offer a level of style isolation that I’ll never achieve without browser support. So, as much as I’d love to experiment with style isolation today it’s probably a frivolous battle until we get native support for shadow DOM.
To get started I created a webpack.config.js
. Within, I was able to set up my dependencies and declare how Webpack would find everything. It looks like this,
var path = require(‘path’); module.exports = { entry: ‘./index.js’, output: { path: __dirname, filename: ‘bundle.js’ }, module: { loaders: [ { test: /\.css$/, loader: ‘style!css’ }, { test: /\.handlebars$/, loader: ‘handlebars-loader’, query: { ‘helperDirs’: [path.join(__dirname, ‘/core/handlebars/helpers’)] } }, { test: /\.yaml$/, loader: ‘json!yaml’ }, { test: /\.md$/, loader: ‘html!markdown!’ } ] } };
With that I could write CSS, HTML (in handlebars), data structures (in YAML), and documentation (in Markdown). This manifests itself into a folder structure such as,
pattern-library |__ card.component |__ card.css |__ card.handlebars |__ card.md |__ card.yaml |__ hero.component |__ hero.css |__ hero.handlebars |__ hero.md |__ hero.yaml
Now I have a .component
that can move around from project to project and when it moves all the necessary styles and documentation move with it. I also have a system that allows me to write card.handlebars
with abstracted template tags that can be swapped on the fly. For example,
<div class="card"> <h1>{{ title }}</h1> {{{ description }}} </div>
And within card.yaml
I may have,
title: Card title description: <p>This is the card description</p>
With these files setup the next step was to tie it all together. That’s where our Webpack entry point comes into play. It does the hard work of fetching the CSS, rendering the Handlebars, and transforming the markdown.
var component = ‘card’;
require(‘./’ + component + ‘.component/’ + component + ‘.css’);
var patternDocs = require(‘./’ + component + ‘.component/’ + component + ‘.md’);
var patternData = require(‘./’ + component + ‘.component/’ + component + ‘.yaml’) || {};
var patternTemplate = require(‘./’ + component + ‘.component/’ + component + ‘.handlebars’);
var frame = require(‘./core/frame.handlebars’);
You may have noticed frame
above, all that’s doing is organizing the dependencies onto the page for someone to see.
This is, maybe, 50% of what I want it to be but it’s showing a lot of promise. I still need to manually adjust the component
to change my view, something I’d prefer to do with a true router/pushState. Also we haven’t done much to style the frame
yet but it’s enough to visualize the shape it could take.
I’ve pushed the code to [GitHub](https://github.com/happycog/webpack-patternlibrary) for anyone who’s interested. It should serve as a good introduction to webpack as well as a boilerplate to get your own little pattern library going.