Web component library

This first (real) article is describing how to create a web component library. There are many resources to be found online. Not all of them are in great detail, many of them about the technical implementation (and less about the pattern), or sometimes only provide partial information on how to do such. Also, I would like to use this first article as a steppingstone for further articles.

Context

Companies working on multiple applications, all a frontend repository of their own, is very common. Multiple developers are working on several shared codebases, with variable timespans in between changes. Developers with different levels of (frontend) skills work on the codebase. The UX has to be identical across applications. When all this applies, setting up a web component library makes sense. If there’s only one frontend repository involved, setting up a web component library still makes sense. But then some parts can simplified, by using a shared folder instead of a complete isolated repository. I will not go into that specifically.

Duplicate, unreadable code

In larger enterprises where I have worked frontend developers are usually understaffed. This is because the web applications supporting business processes at those companies were developed some years ago. Back then web applications relied heavily on serverside generating of web pages. The role of the frontend developer was merely to style the pages. Most of the work involved only HTML, css and images. So a few frontend developers made sense, since there wasn’t that much to do.

But as the possibilities clientside grew (especially in the field of javascript), the overview clientside decreased. Frameworks like jQuery, great as selector framework, didn’t prevent spaghetti code. Developers who not understood the purpose of this code or simply not cared started copy-pasting, creating duplicate code. When in such situation other developers continue working on the code, unaware of the code’s origin, the code will be adjusted but not at all places where this code occurs. This creates a hard to maintain codebase.

Also, javascript and css tends to feel messy for non-frontend developers. Weakly typed. Very forgiving browsers (but just not when you expect it). Strange quirks required to make css work in all browsers. Many different frameworks (some not very opinionated) and exotic combinations… A great formula for incomprehensible code.

Web component library

Web component library – from wikimedia commons

Requirements to improve frontend

In order to prevent this mess, a single origin for all these coherent code fragments is required. Also, this code ought to be as easy to reuse as it is to write plain HTML. Especially when the availability of frontend skills is limited this becomes very important. These code fragments, web components so to say, need to have the following features:

  • All nastiness of javascript, css and browser quirks abstracted away from the application’s code
  • Able to reuse them everywhere throughout multiple applications
  • Easy to understand how to use them for non-frontend developers

Abstract away all nastiness

A not completely implemented technology is web components. And especially the custom ones are interesting. Basically it allows a developer to implement it’s own HTML element with custom behaviour (javascript) and styling (css). The nice thing about these web components is that they are natively supported by browsers. The downside is that web components are still in an experimental phase. However, there’s no need waiting for this pattern to be embraced by all major browsers. Even with a selector framework as jQuery it’s possible to construct your own custom web components. For example:

(function($) {
  $('my-own-component').append('<div class="my-own-component">' + $('my-own-component').html() + '</div>');
})(jQuery);

This allows you to use the following HTML (which is perfectly allowed within HTML5):

<my-own-component></my-own-component>

Above code is a very poor implementation. It doesn’t take into account multiple instances of my-own-component. It’s digging through the whole DOM. No namespacing or prefixes are used both for the custom HTML element as well as for the css. There are probably a bunch of other anti-patterns the snippet is using. However, the idea is that you can define your own custom HTML element in order to abstract away unwanted complexity of the frontend. Even with a framework like jQuery. The code above has abstracted away most of the complexity in a single HTML tag. With more opinionated frameworks the required code is much more elegant, however not subject of this article.

Reusing your custom web components

In order to keep the amount of time for maintaing components as small as possible, reusing components is key.

File per component

The first step is to extract the code that needs to be reused to a separate file. This way the file can easily be included when required. Also, the amount of code per file ought to remain small. That way it is easier getting an overview of what that file does. Make sure the purpose of the code is unambiguous to help further with clearifying the overview. When all code in a single file is coherent, we can talk about a component.

On build-time concatenate all files of course to minimize the amount of http requests required.

Separate folder for reusable components

In order for other developers to recognize a component, simply put the component in a separate folder with other components. Name the folder accordingly (like shared, commons, components, whatever). You might distinguish between reusable components for different levels. Components for a page or screen, for an application or even for multiple applications. Be sure to put some guidelines in place for naming them and their folders. This way the shared components and on which level they act are identifiable without documentation.

When the components are being used across multiple page and applications, the UX department will be happy. Namely, this increases the consistency of the behaviours and styling . Also, it is easier to adjust the UX across the complete application since there’s only one source.

Modularized components

There are several ways of creating a modular component. The simplest way is to use prefixes or namespaces throughout your components for styling, and the new import syntax provided by ES2015. In combination with a module bundler (like Webpack for instance) it is possible to import scss and HTML in javascript components. Per javascript component only the dependencies (whether these are templates, styling rules, other javascript components or assets like images) that are required for that component are imported. Which is great, because in combination with ‘File per component’ the scope of the component is limited to what you see in that file.

// Import module dependencies
// The .js of javascript files may be omitted in Webpack
import '../shared/simple.module';
import '../../node_modules/external-lib/dist/external-lib.module';

// It's own component (look, in a separate file)
import {ComplexComponent} from './complex.component';

// Even import specific styling
import './_complex-component.scss';

angular.module('complex', [
  'external-lib',
  'simple'
  ])
  .component('complex-component', ComplexComponent);

The code is AngularJS 1.5.x in ES2015 syntax. Say the file above is called complex.module.js, then we’re now able to import it as dependency in other modules in the same manner as the simple.module.js was reused. This enables usto use the custom HTML tag <complex-component> in our templates (its behaviour is defined in the ComplexComponent, which on its turn is most likely using an HTML tag <simple-component>). In above exampe the actual implementation of the component is decoupled from its module dependencies.

Making components modular enables developers to integrate them in code (in other components for example) much smoother. Design the components with sensible defaults for optional parameters in order to smooth integration.

As long as the shadow DOM and the CSS scoping module is not (fully) implemented in every browser, it’s good practice to prefix or namespace your HTML components with classes. Within scss developers are able to nest these namespaced or prefixed classes. Then it can be made sure the browser does not apply any styling rule outside its meant scope.

<div class="container">
  <div class="prefixed-element">
      <!-- Nest all styling that should not leave this element within .prefixed-element -->
  </div>
</div>

 

// Inside a .scss file
.prefixed-element {
  // All style definitions nested here are scoped to its parent
  ... 
}

Unit testing and a sandbox environment

In order to guarantee backwards compatibility, implement unit tests. Also, unit tests help thinking ahead multiple scenarios. In combination with a separate repository and a controlled sandbox environment, unit tests enforce developers to write modularized components. As a bonus: on top of the sandbox environment a living styleguide or component guide can be written (see Living style- and componentguide).

Separate repository

When the components are to be used throughout multiple applications, developers might end up synchronizing the components (folders) manually. With two applications this is already terrible, let alone for more than two applications. One could link a folder locally to another project where the components are maintained. But this requires (manual) local configuration, which we tend to avoid for the sake of ease of use.

An elegant way around this problem is putting the web components in a separate repository. The repository or its produced artifact can then be imported as dependency for other repositories (like frontend applications). First exporting the repository or its artifact to a centrally hosted repository (like Sonatype’s Nexus or JFrog Artifactory, or even npmjs.com itself) makes it easy available for other repositories to import it.

Governance

To keep control over the extracted component repository, make sure to put in place some governance:

  • Determine who has ownership over the library
  • Determine how to release new versions of the library (semver for npm is an interesting read)
  • Decide when a repository becomes too large. Additional repositories can be created or the number of artifacts can be increased (one could go as far to create a separate artifact per component with its own version)
  • Decide how to enforce feature teams to update older versions of components. Especially when newer versions are not backwards compatible and the older versions are not actively maintained anymore.
  • Decide what to put in the repository (just components, or also styling-only ‘components’ like reusable css)
  • Determine when to promote or demote a component to a higher or lower level, and how to enforce this. A component can be created for a screen or page, for an application or for an entire application landscape. One could promote a component to a next level when it’s needed across screens or applications. However, for its exposure it might be better to promote the more ambitious components already to the highest level. Just make sure the component is not too bloated.

Living style- and component guide

A key successfactor for components is how familiar they are to their users (mostly developers and UX, business slightly less), and the ease of integrating them. What helps massively is a user-friendly guide on how to use the components. Living style guides are already very popular. Living component guides with clear examples and fiddle boxes are a natural extension of that. When the guide(s) are deployed on a central server (or even exposed to the outside world like Twitter’s bootstrap) non-developers like the UX department and business can take a peek as well.

For UX it’s helpful to see what’s already available and what can be reused (or even referenced from wireframes). Or to determine the impact of changes in the corporate identity. The business can determine on a more functional level what’s already there and how much some new feature might cost (especially when componentizing larger chunks of code containing business rules, moving towards something like a living documentation – but be careful, usually this is an anti-pattern for modularization because of additional dependencies on services for example, reducing a component’s flexibilty to integrate). Or just to get inspired.

Wrapping up

Web component repositories hosted centrally, designed correctly, are a bless for every developer. Every organization dealing with multiple frontends ought to consider a web component repository, hosted centrally. Its success depends on the guidelines described in this article. Make sure to consider them before implementing one.

Facebooktwittergoogle_plusredditlinkedinmailby feather

Leave a Reply

Your email address will not be published. Required fields are marked *