Comparing Web Components: Part 1 – Vanilla JS

his is the first in another sequence of learning for me. The topic is web components. When I was doing initial research, I loved the idea of web components and figured out how to use them via Polymer. However, Polymer is not the only library out there. I also have a build system to consider. I want to write code in ECMAScript 6, CSS in less and incorporate libraries with jspm.

My first stop is to add the Web Components Polyfill to my project. Fortunately, the Web Components team releases the polyfill via Bower and NPM. Since it is an NPM package, I can easily install it with:

jspm install npm:webcomponents.js

I then need to add the library to my Areas/Main/Views/Layout.cshtml file:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="~/jspm_packages/npm/font-awesome@4.3.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- Required Polyfills -->
    <script src="~/jspm_packages/npm/webcomponents.js@0.6.0/webcomponents.min.js"></script>

    <!-- Components used -->
    @RenderSection("htmlelements", required: false)

    <div class="flex-container">
    @RenderSection("scripts", required: false)

Note that I’ve also added a htmlelements section to the page. This allows me to bring in the HTML custom elements that I want to use within the view.

Vanilla Javascript

I fully expect to be using a library rather than plain Javascript. However, one must have an appreciation of what is going on to understand what is not going right when things go bad. Fortunately, I have a template for what I want and I cut and paste it from, with a couple of changes. My Areas/Main/Views/Home/Index.cshtml looks like this:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<nolib-helloworld>No Library</nolib-helloworld>

@section htmlelements {
    <link rel="import" href="~/elements/nolib-helloworld.html">

Once I had a web component that was hand crafted working, I turned my attention to the build system for components. The idea is to be able to handle the stylesheet in less and the code in ECMAScript 6 (so that it goes through babel), then combine all of the pieces together at the end into a HTML import. First step – separate out the concerns so that I have something to build. I created a directory src/elements/nolib-helloworld to hold the pieces. There are three parts to the example web component I downloaded. Firstly, the Javascript code goes in nolib-helloworld.js:

(function () {
    // Find the template for this HTML element
    var template = document.currentScript.ownerDocument.querySelector("#noLibHelloWorld");

    // Create the prototype for the new HTML element
    var elementPrototype = Object.create(HTMLElement.prototype);

    // Set up lifecycle callbacks for the new HTML element
    elementPrototype.createdCallback = function () {
        // Create the shadow DOM and clone the template into the shadow DOM
        var shadow = this.createShadowRoot();
    document.registerElement("nolib-helloworld", { prototype: elementPrototype });

The less code similarly goes into nolib-helloworld.less:

.outer {
    border: 2px solid brown;
    border-radius: 1em;
    background: red;
    font-size: 20pt;
    width: 12em;
    height: 7em;
    text-align: center;

.boilerplate {
    color: white;
    font-family: sans-serif;
    padding: 0.5em;

.name {
    color: black;
    background: white;
    font-family: "Marker Felt", cursive;
    font-size: 45pt;
    padding-top: 0.2em;

Finally, the HTML code (nolib-helloworld.html) is much reduced and includes the CSS and compiled Javascript:

<template id="noLibHelloWorld">
    <link rel="stylesheet" href="nolib-helloworld.css">
    <div class="outer">
        <div class="boilerplate">
            Hi! My name is
        <div class="name">
<script src="nolib-helloworld.js"></script>

Building a Web Component

I need to augment my build process to handle the building of web components. I’m going to use gulp-vulcanize, so add that to the package.json as a devDependency and require it in the Gulpfile.js.

Building components needs to be a two-part process. Firstly, I pre-process all the files into a temporary area. Secondly, I vulcanize the pre-processed files into the web root area. The vulcanize tool (and the gulp plug-in) are written by the same guys who write Polymer, but it isn’t limited to Polymer usage.

Starting with the pre-processing, I have three tasks in Gulpfile.js – one for each type of file:

gulp.task("build:components:copy", function () {
    return gulp.src([ "src/elements/**/*.html", "src/elements/**/*.css" ])

gulp.task("build:components:less", function () {
    return gulp.src("src/elements/**/*.less")
        .pipe(autoprefixer("last 2 versions", "> 5%"))
gulp.task("build:components:js", function () {
    return gulp.src("src/elements/**/*.js")

The less files are fed through less and autoprefixer before being minified and stored in the temp directory. The Javascript files are fed through babel before being stored. Finally, the HTML files are just stored in the temp directory. If I have any CSS files that don’t need pre-processing, I’ll store those as well. With the temporary area populated I can now vulcanize the files:

gulp.task("build:components", [
], function () {
    return gulp.src("temp/**/*.html")
            dest: "wwwroot/elements",
            inline: true,
            strip: true

This will make the nolib-helloworld.html appear in your wwwroot/elements directory. A side note – I already have wwwroot in my .gitignore file but I added temp to the .gitignore file as well. I also included a clean:components task in Gulpfile.js to clean up the generated components files.

Running the project now, I get a nice display:


The code has been checked in to my blog-code repository with tag cs-0.0.2.

That’s one down and three to go: Polymer, X-Tag and Bosonic libraries are up next.