I Ching App with Polymer and ES6

We recently developed an I Ching app utilizing Polymer and ECMAScript 6, and I wanted to present some of my thoughts on the development experience using these technologies.

This is not meant to be an exhaustive tutorial on either Polymer or ES6, as you can simply search and find a myriad of helpful tuts on the web, but rather a short reflection on how using these frameworks/features can enhance (or hamper) your front end based web applications.

You can check out the app here: I Ching

And also check out the code on: Github

First of all, in case you’re unfamiliar, the I Ching, or Book of Changes, is an ancient Chinese divination text. Divination is a way to gain insight into a question or situation via ritualistic or “occult” (or some might say spooky like voodoo or some creepy, weird crap like that!) means. Famous examples of divination are astrology or the tarot.

Anyway, to consult the I Ching, one uses one of two techniques (we implemented the coin technique) to produce six lines, either solid, broken, or changing – meaning either a solid line “changing” into a broken line or vice versa.  These six lines, read from bottom to top create a numbered “hexagram”.  The actual I Ching text is simply a compilation of these 64 hexagrams with corresponding bewildering and befuddling commentary for each (I challenge you to understand what it means!).

So the long and short of it is you ask a question, throw your coins six times to get a hexagram, look up the hexagram in the text, and read the corresponding commentary for your answer.  Simple enough, right?

Polymer, if you haven’t heard of it before, is a front end framework which is essentially a Web Component polyfill with some extra features thrown on top.  I’ve been intrigued by Web Components for quite while ever since I’ve came across them a couple of years ago and how they will potentially dramatically change the way we architect and develop code on the browser. I won’t go into too much detail about them, as you can simply read up about them yourselves, but they are a future collection of standards that are still getting approved by W3C and are slowly being adopted into modern browsers. Chrome as of this date is the only browser to have complete support for Web Components.

Web Components revolve around custom HTML tags, Shadow DOM, HTML imports, and the template tag.  Think of them as fully encapsulated UI features that can be simply inserted into your web page by including a custom tag in your HTML, kind of like a jQuery plugin.  Here’s a quick and dirty example.

Let’s say we want to make a new component called iching and use it in our site:

<head>
  <link rel="import" href="path/to/component/iching.html">
</head>

<body>

  <!-- This will do something -->
  <iching></iching>

</body>

The component’s functionality would be triggered simply by including the custom tag, while the components corresponding code is pulled in via the HTML import as seen above in the head.

The code in the iching.html file would look something like this.

<style>
  button {
    color: red;
  }
</style>

<template>
  <button id="myButt">Clicky</button>
</template>

<script>
  document.getElementById('myButt').addEventListener(function(){
    console.log('clicky');
  });
</script>

That code doesn’t really do much of anything, but it conveys the basic paradigm of Web Components. The markup contained in the template tag would be inserted into the iching tag, with the corresponding scripts and styles (which can utilize external files opposed to being inline just as easily) going to work on it.

The really cool thing about all of this is that the markup within the component is only accessible (well almost, there is a loop hole) by the scripts associated with the component, aka Shadow DOM. The styles rules would also only be applied locally. So basically we get fully separate and encapsulated UI pieces that don’t clash and step on each other’s toes and a much cleaner HTML file free of endlessly nested divs. Yay!

The one necessary feature Polymer added that doesn’t exist in the Web Components standard is data binding in the template tag to dynamically render views (more about this later).

As far the actual application goes, almost all of the logic is written entirely in the front end, with the only back end piece being a simple service that returns the hexagram commentary pulled from a JSON file.

The app is broken down into several different logically separated components. I decided to include all the styles and scripts associated with each component in a separate file because inline makes me feel a bit weird and uncomfortable. Each component communicates with one another through custom events running through a global event bus/emitter.

Easy peasy right?

Everything was going smoothly until I decided I wanted to use ES6 syntax. That’s when things got tricky.

ES6 is the lastest version of ECMAScript, and introduces a whole slew of features to the JavaScript language that will make JS coding look and feel a lot different.

Right now most of those features have only a smattering of support across modern browsers (mainly Chrome and Firefox), so a transpiler is required to write code in that syntax. I decided to use Babel over Google’s Traceur admittedly just because it seemed trendier and had a nicer looking site.

I think ES6 is great and adds a lot of useful features that improves JavaScript coding. Though most of the features we ended up using were quite trivial such as let, const, arrow functions, enhanced object literals, and rest/spread. More advanced features weren’t used like generators or proxies (which is not even able to be translated in ole’ ES5).

The main thing that made things difficult with Polymer was using ES6 modules. Babel won’t transpile ES6 modules directly into ES5 but instead into modern module formats such as CommonJS or AMD. I decided to go with CommonJS which meant using Browserify. This was all handled with Gulp running Browserify with a Babel transforms.

Because of the component application structure, it seemed more logical to create separate bundles for each component rather than a singular application bundle. This, however, failed to work as each component needed to share a global module (the event emitter). Creating separate bundles meant creating duplicates instead of the shared module, which made the app incapable of sharing state between components, so one global app bundle was necessary.

Polymer requires their components to be registered with JS in their HTML imports file, but each component referencing the same bundled JS file would not work. Instead, each component had to be registered from one application entry point file. This caused problems on Firefox and Safari because the bundled code would run before the Polymer source JS code (pulled in as a HTML import from every component’s HTML file). As a result, for local development, we had to run Polymer’s Vulcanize build tool which inlines every HTML import file into the main HTML file (which is ideal in a production environment to reduce network requests).

All in all, getting all this stuff to work together was a huge pain in the ass, and Polymer and the ES6 transpiler seemed very unnatural together.

In general, I like how Polymer allows us developers to use Web Components in browsers that still don’t support them. My main complaint with them is that their templating engine (for data binding) is pretty limited compared to something like Angular’s (which they state is for performance reasons in their docs). Nested object properties won’t auto-render on change, so you manually have to trigger the event in the code, since they don’t use dirty-checking like Angular. Also, template braces must encompass the whole attribute or content of a tag, which annoyingly makes simple tasks such as adding a class (which in both Angular and Handlerbars, with helpers, able to be confined in the template logic) resort to DOM querying.

I have to admit I initially wrote the code in plain jQuery, and it was a whole hell of a lot easier to get it working. Of course this app is quite tiny compared to most things, and a huge jQuery app would get out of hand really fast.

It was a fun experience to build something in a new way that I hadn’t tried before. On the other hand, a part of me feels like ultimately all these frameworks are just variations of accomplishing the same thing.

I mean at the end of the day, all that matters is product right?

I guess it all depends on who you ask.

Advertisements