Monday, March 13, 2017

Polymer in Production

When I was tasked with including new functionality into an existing, rather big internal web application, I found myself in a bit of a dilemma.

For my own personal projects and several other internal projects I did at work, I have grown to love web-components using Polymer because of the ease of development and the natural way to structure applications into (re-usable) parts.

The existing web application in question had been mainly developed with a once (and still) very popular JavaScript library.

A full rewrite of the application was out of question due to time and budget restraints, but using Polymer would have a lot of benefits for the future as far as testability, maintainability and extensibility are concerned.

In this blog post I will go over some of the things I did and had to consider to make this work.



Web components are web components

Now the nice thing about web components is, that they are just that. With some prerequisites provided, you can use them like any other HTML element, e.g. an <input> or a <div>.

To make web components work across browsers, you first have to make sure that the necessary polyfills are loaded. You can then import your web component definition in your HTML document:

And you are all set to include your custom elements in whatever template system you are using or dynamically add elements:

Data-binding

One of the nice features of Polymer on top of the web components standards, is the easy declarative way to do (two-way) data binding, but this only works inside of Polymer elements.

To pass data between your existing app and the Polymer element you will have to do some extra work.

Getting data into a Polymer element is a simple matter of setting a property or attribute.
As an example let's assume we have this simple but amazing <my-name> element:

We have included this element somewhere in our page like this:
To update the element with the correct name, e.g. if a user signs in to our page, we would have to do something like this:

For sending data out of the element you have at least two possibilities, both of which are based on events.

If you have a property with notify: true Polymer will automatically generate 'my-property-changed' events that you can bind an event listener to.

In the element:
In your code outside the element:

You should be aware though that the data you get in the event handler can be different for sub-property changes in objects, and changes in arrays: Reference in the Polymer documentation

You can also send custom events from your element and listen to them from the outside if you need more control about when to notify the parent application about changes.

Polymer 1.x:
Polymer 2.x
Listening to the event from the outside:

CSS fun

While everything so far is quite easy and seamless to implement you might still get an unpleasant surprise the first time you open up your website in a browser that doesn't yet support Shadow DOM natively. Without the Shadow DOM boundaries in place all your original CSS will leak all the way into the deepest parts of the local DOM tree, which might yield some really interesting and unexpected results, especially if you are using very generic class names.

To prevent this you will have to pack all your normal CSS into a custom-style.

Polymer 1.x:
Polymer 2.x:
If you want to keep your CSS in an external file you will first have to convert your CSS file into a style module...
...import the style module file...
...and include it in your custom-style.

Polymer 1.x:
Polymer 2.x:

If you want to keep the styling across your application consistent and don't want to copy all the styles you will have to go one step further by splitting your style into two style modules, one module for the styles that only apply outside of your elements, e.g. the layout of the page, and a shared style module that includes your font-styles, colors, spacing, etc. You can then include the shared style module in both the custom-style of your main page and the styling of each element where you need it.


But wait... there's more

Using the techniques I showed so far you can slowly but steadily replace bits and pieces and even whole modules of your application with web components.

But you can also work your way from the outside inwards. What I did for the application I'm working on is to replace the layout and navigation with app-layout and app-route. This also had the extra benefit for this application to turn a fairly static layout into a more responsive one.

There are some other things to consider depending on what your current build/deploy process is to include the Polymer build process into it. This gets especially important with Polymer 2.x around the corner where you might have to compile ES6 code to ES5 to make sure the application still runs on IE11, which unfortunately is a requirement I have to fulfil. But that's another story for another time...