Web Components: Moving Beyond React

Kurt Cagle
The Cagle Report
Published in
10 min readJul 30, 2017

If you are a web developer, chances are pretty good that you’ve become adept with React, Facebook’s view layer technology that has turned JavaScript and Node into one of the hottest combinations to tempt a VC’s pocketbook. For those of you not familiar with React, you can think of it as a way to build components that react to changes in data state in web applications, part of what is commonly called a model-view-controller design pattern. The model is the data and its associated structures, the view is how that data gets represented, and the controller is the layer that mediates between the two.

I’m going to go on record taking what I suspect will be an unpopular stance. I don’t like React. I’ve been working with it for a few years now, and yet I find that I haven’t hit that Aha! moment when suddenly the language crystallizes for me, where I realize that there is an elegant simplicity that I simply had to train my brain right to find. For a while I saw React as a necessary evil, because it did solve certain problems that were very much issues even as much as a couple of years ago, but I think that React (and quite a few other node-based frameworks) will in the very near future start fading away. Ultimately, the vehicle for that will be a little sleeper technology that’s just now beginning to make its debut: Web Components.

The Rise of W3C Web Components

The idea behind web components has been floating around in one form or another since the late 1990s, and is really quite simple. A web component is simply an html-like tag in a web page (or similar markup) that displays content in certain ways and performs certain actions, but is not defined as part of the standard markup language. What makes such components so exciting is that the “framework” necessary to make this happen should become native to most browsers within the next couple of years, which means that rather than building complex server side compile applications, such web-component based forms have tiny footprints, stunning performance and ultimately cross-browser compatibility — all of which were reasons that so many people moved to React and similar tools in the first place.

To give an idea about why this is such a big deal, consider an application I wrote recently. The need behind it was simple — I wanted to create a text box that would let me enter tags using the hash symbol (a.k.a. hash tags) that would then become live buttons for bringing up an external web service, here a dictionary entry. This ultimately ended up requiring three components — one that let people enter the text and generate the tags as output, one that displayed a dictionary entry, and a third that retrieved a list of alternatives if no definition was found for that term. The back end database that powered this was provided by Merriam Webster.

This example can also be seen working (for Chrome users only) at https://codepen.io/kurt_cagle/pen/KqLagb.

The beauty of web components can be seen in the markup that describes the above application:

<link rel="import" name="kurt-app" href="kurt-app.html"></link>
<kurt-app>
<kurt-headline level="1">Tagger</kurt-headline>
<kurt-appcontainer>
<kurt-tagger id="tag1">
This is an #active #web #component. You can type into the
#text_area (this #pane), and every #hashtag (#) will become a
#button that returns a #dictionary entry.
</kurt-tagger>
<kurt-defs id="defs1"></kurt-defs>
<kurt-suggest id="suggest1"></kurt-suggest>
</kurt-appcontainer>
</kurt-app>

This is what a web component applications can look like. It is “nominally” in HTML, if you look at the web component foundation as being an extension of the HTML space. The elements are labeled with some kind of identifier (here ‘kurt-’) that serve to identify a library of components in my particular domain (what in XML terms would be considered a namespace prefix). The first line — the link import statement — brings the app into the current page, and at each linked page related links make up sub-components. For instance, the component that displays a definition is a separate file (kurt-devs.html) that contains both the script definition and the style and structural form of the component.

<script> Element `kurt-defs` (class Defs extends HTMLElement 
{
constructor(){
super();
const t = kurtDefsTemplate;
var clone = document.importNode(t.content, true);
this.appendChild(clone);
this.termsTemplate = Template `term`;
this.defsTemplate = Template `defs`;
this.style.display='none';
}

load(obj){
this.base=obj;
var entries = this.base.entry_list.entry;
if (!this.base.entry_list.suggestion){
var entries = Array.isArray(entries)?entries:[entries]
var name = entries[0].ew;
var pos = "["+entries[0].fl+"]";
var pronounce =entries[0].pr;
var et =entries[0].et+""; this.termsTemplate.bind({
name:name,
pos:pos,
pr:pronounce,
et:et
});

var defs = Array.from((""+entries[0].def.dt)
.split(/[:]/).slice(1))
.filter((item)=>(item.length>5))
.map((item)=>{return {def:item}});

this.defsTemplate.bind(defs); this.style.display='block';

}
else {this.style.display="none"}
}
});
</script><template id="kurtDefsTemplate">
<div class="defs-container">
<template name="term">
<div>
<span class="term">{name}</span>
<span class="pos">{pos}<span>
<span class="pr">{pr}</span>
</div>
<div class="et">{et}</div>
</div>
</template>
<ol class="def">
<template name="defs">
<li>{def}</li>
</template>
</ol>
</div>
<style>
.defs-container {
border:inset 2px gray;
width:400px;
min-height:200px;
padding:5px;
}
.def {}
.term {
font-weight:bold;
text-transform: capitalize;
}
.et {font-style:italic;
margin-top:5px;
margin-left:5px;}
</style>
</template>

These component are modular — stylesheets, for instance, only apply to the components where they are defined. Additionally, templates can be used to promote data binding, associating both getters and setters in the associated class with variables, and making it possible to bind Javascript objects (and object arrays) with specific sub-templates. This can be seen specifally in this part:

<ol class="def">
<template name="def">
<li>{def}</li>
</template>
</ol>
<script>this.defsTemplate = Template `defs`;var defs = Array.from((""+entries[0].def.dt)
.split(/[:]/).slice(1))
.filter((item)=>(item.length>5))
.map((item)=>{return {def:item}});

this.defsTemplate.bind(defs);
</script>

The defs array does some cleanup from the data source (loaded in earlier) and has the form:

defs = [{def:"This is definition 1"},{def:"This is definition 2.",...]

The statement this.defsTemplate,bind(defs) then iterates through the definition array, looking for the def property and passing the value into the {def} element in the template.

Web Components vs. React

There are many other aspects to web components that are worth digging deeper into, and will likely be fodder for future articles. However, in this post, I’d like to consider why I think this will have such a big impact upon web development vs. React, looking at what many consider the strengths of React.

Separation of Concerns

React works by focusing specifically on the View aspect of the MVC paradigm — you have a single overarching data model, then when something changes in the model, React acts as the controller to modify the view. However, it also places the onus of managing state into the hands of the developer, and despite a design philosophy to the contrary, the reality is that much of this state management could and should be more readily be handled within an encapsulated environment.

Javascript has also been evolving to better handle asynchronous events well, especially with the advent of both Promises and async variables. The Web Components (WC) approach lets you create composable applications without the need for heavy state management. React requires MobX or similar state management APIs. A WC approach, on the other hand, lets the component manage it’s own state, hence only needing to be written once.

This also works better when dealing with immutable data structures — if you essentially treat what data comes in from the outside as static, then any output (created by using the immutable streams to build new structures) will always be both declarative and consistent — there will be no unexpected side effects.

In practice this means that a web developer can create a component (with the assistance of a UX designer), and make it available as a library, then a web author can just use that component, without needing to know its inner structure or working mechanisms.

Ease of Development

React (with an add-on Javascript Extension (JSX) library) can be used to quickly prototype components. It uses an HTML-like language to bind attribute properties, and state changes can occur when you modify the properties of the state object, and React builds a specialized style language for setting changes in appearance

Web components don’t need an HTML-like language to build templates, because they use HTML itself. Web Components are easy to write. After a couple of years, I still stumble over some arcane aspect of React that I “should have known”, in part because there are so many different state management libraries that each impose their own requirements, in part because there are many places where the HTML-like language is not in fact all that HTML-like.

With web components, I was writing basic components in a few hours and reasonably complex ones (such as the one above) in a few days. These components are fun to write, and code reuse is high — I’m already building web applications that I’ve been struggling with in React in days rather than weeks. What’s better — I don’t have to spend so much trying to figure out various support libraries that have poor documentation, or spend all my time compiling.

Performance

React’s biggest claim is it’s ability to create a separate shadow DOM that is used to make changes, then only modify those things in the live DOM that have changed in the shadow DOM. This results in significant performance improvements, even despite the cost of managing the shadow DOM.

In practice, in Web Components a template is an inert DOM, but can be used at various levels within a given application. The Template literal operator lets developers create a duplicate of the template (using one of the slickest bits of TemplateLiteral programming I’ve seen to date), make changes to that, then either insert or replace live nodes in the document when everything is ready. Mostly, this process is very transparent — and very, very fast.

Web Components are something that will be built into the browser. Currently for Chrome and Firefox there are small polyfills because not everything is supported yet, but much of it is. Microsoft is also heavily engaged in working with web components, and has been an active participant in the W3C Web Components (W3C-WC) group. This means that the amount of information that needs to be sent over the wire is tiny — in some cases only a single TCP/IP packet.

In a number of benchmarks I’ve seen, a W3C-WC version of a web application is in and rendered before the React based version has completed loading, and once loaded, both can make use of caching to reduce transmission latency. React components run through node can take a while to compile, and while the React library itself . W3C-WC components, on the other hand, piggyback on the browsers’ support for debugging.

It is worth noting as well that Web Components can be served up by any server, not just nodejs, and in theory can also be precompiled into the javascript package — it just doesn’t have to be. Since the bulk of web component code is built into the browser, such compiled web components are usually very lean and have much less likelihood of collision, especially with larger projects.

Browser Support

Because React is precompiled, multiple versions that facilitate different browsers can be produced without additional code on the part of developers. It was in fact this need for optimization of browser specific code that justified an HTML-like layer in the first place. Given the rapid change in the Javascript framework in the last few years, this was an unavoidable requirement.

However, there are distinct signs that the previous rapid pace of Javascript evolution is slowing. Most of the “to-do” items on the Javascript roadmap from 2015 have been accomplished, and what is left are very much edge case issues with respect to the browser (the introduction of fixed byte-width data types being the most significant).

This in turn has focused attention to the web components layer. At this stage, Microsoft has been engaged in a significant rewrite of their underlying DOM Architecture in preparation for this (most especially in areas such as the Shadow DOM and CSS Custom Properties) and Mozilla, Google and Apple have been working closely on keeping both the specification consistent and building this component architecture into their respective browsers.

Google Chrome is perhaps the farthest publicly along in this regard. Mozilla Firefox has also been working heavily on this specification, though for the moment these are hidden behind a custom flag (see https://developer.mozilla.org/en-US/docs/Web/Web_Components):

The snuggi library provides a thin up-to-date support for Web Component features in Chrome specifically, and was used for the application discussed earlier:

<script src=”https://unpkg.com/snuggsi">

This last point means that in this one crucial area, Web Components are not yet ready for prime time, though that should change by late 2018 or early 2019. The primary blocker to date is support for shadow DOM, which is where most development efforts are now going. This makes it a good time for web developers to start becoming proficient with the tech, especially in the Chrome ecosystem.

Implications of Web Components

As web components become more heavily adopted, one effect of this will be a shift towards the development of WC component libraries. Currently this exists on the back end for Javascript by itself, but the W3C-WC spec opens up adoption of an import style to make requests for specific library components within a web browser. Because such products are self contained (and perhaps self-documenting) they can be downloaded independently of one another, which reduces potential code version problems.

Another area where I believe Web Components will represent a huge win will be in the domains of code security and licensing. Because these are self-contained units, such components can be certified and have an encrypted hash associated with them through certification boards (most likely private). Similarly this makes monetization of component libraries easier, in which basic capabilities may be freely available but advanced capabilities may be opened for a licensing fee.

Overall, though, I believe that web components represent the final evolutionary stage for web client development. They can be developed inline, can be imported, can even be compiled. They can be combined with one another, communicate with one another, and can be responsibly forked and versioned. It’s a compelling version for the web, and one that I think we are close to achieving.

Kurt Cagle is a writer, blogger and information architect, who has been writing on web related technologies for more than thirty years. He lives in Issaquah, WA, with his family and cat Bright Eyes.

#javascript #react #json #webComponents #w3C #TheCagleReport

--

--