A look at Stencil.js

By Rob Bearman on October 2, 2017

Stencil.js was introduced recently at the latest Polymer Summit. Some of our partners had questions as to what exactly Stencil is, what it creates, and what are the implications of its use. We thought we'd have a look. Here's what we discovered.

What Stencil is

Stencil is three things:

  1. A component framework, similar in intent to Polymer and Skate.js, for building web components using Functional Reactive Programming (FRP) techniques including state-triggered render methods
  2. A build system that leverages ES7 decorators through the use of TypeScript, Rollup, Webpack, and Babel
  3. An optional application framework

What Stencil is not

  1. A framework for building any other type of component than web components
  2. A component framework that produces web components supporting Shadow DOM

Details

Stencil provides a fairly immersive development environment which is installed via a clone of either their application starter project, or a simplified component builder project. The former allows you to build web components within the context of an application, presumably where there is a tight coupling between component design and application needs. The latter appears to be a more standalone approach to building web components.

There is a heavy influence of React here, with the application starter project feeling similar in nature to Facebook’s create-react-app project template. Beyond the development environment particulars, Stencil leans on React-like idioms for binding component state change to a render function that outputs JSX.

This is a similar approach to web component architectural design as Skate.js with the recent difference of Skate’s offering of pluggable renderers (JSX, lit-html, template strings, etc) versus Stencil’s fixed reliance on JSX. Skate appears to offer a much reduced development environment beyond the JavaScript libraries it provides for its implementation.

Stencil specifies a canonical class model for defining a web component, relying on ES7 decorators for signaling to the build system how the resulting definition is to be assembled with Stencil library routines. The result is then transpiled into ES5 JavaScript consumable web component code, coupled with demand-loaded polyfills where required. Stencil refers to this build pipeline as a compiler.

Where the “compiled” aspect comes in is the binding of the Stencil component definition code with library code that somewhat opaquely provides partial-specification web component support. More on that later.

Frameworky stuff

The Stencil component class template is an abstraction that binds with Stencil library code. In this sense, Stencil is a framework and the usage of the Vanilla JavaScript™ terminology feels a bit like a cheat, if you’re of the opinion that Vanilla JavaScript implies the code is all in front of you as a developer with nothing tricky up the sleeves. In the sense that it has nothing at all to do with Polymer and Polymer’s tricks, then, yes, it’s vanilla. The discussion of what should define a Vanilla Javascript component is probably worth a blog post of its own.

But as an example of this sleight of hand, Stencil builds components that do not make use of or rely on the Shadow DOM portion of the specification, resulting in custom elements alone, yet it magically supports the use of the <slot> tag. It does so by providing framework/library code that parses for named slots and manages the child element merger on its own. Whether the full, expected functionality of slots under Shadow DOM is supported, experimentation and probably more than a little cold sweat might be called for.

There are other examples of this sort of polyfill/framework/non-vanilla construct within Stencil’s definition/bind-to-library/transpile lifecycle, including enforcing property immutability within a component’s internal code, but the key point in analyzing Stencil is to recognize it’s not just an ES5-generator for web components (as well as, don’t forget, not a React component generator, or a Vue component generator, etc, etc). It’s an opinionated framework.

The documentation describes the use of several decorators for fleshing out a component’s definition:

Stencil also provides hooks for specifying web component lifecycle callback code.

Further in the way of framework flavor, Stencil provides mechanisms for rendering Stencil web components via server side rendering, and for generating pre-rendered static html+css pages. Stencil also provides objects for integrating with Node.js/Express.js web servers.

The inclusion of an add-on stencil-router is an additional reminder that Stencil is as much about building Stencil-based applications as it is about generating web components.

Distribution of Stencil components

Stencil provides a non-transparent means for setting up Stencil components for distribution. It’s non-transparent in the sense that it relies on its build tools coupled with a stencil.config.js configuration file and expected additions to the project’s package.json file. Once published to npm, the component package can be referenced through HTML via:

<script src='https://unpkg.com/my-name@0.0.1/dist/myname.js'></script>

In a Stencil application, a published and npm-installed component package can be accessed through the application’s stencil.config.js file where the components to be “imported” are added to the collections key. It’s not apparent to me whether JavaScript import is supported.

Summary

As a development platform, Stencil.js looks as enticing as React in that expressiveness through abstraction and FRP idioms make reasoning about the architecture easy. The toolset is impressive as a means of building web component based web applications, and feels like the result of a team actually dogfooding their own products against it - just as the Stencil team suggests in their talks.

The potential drawbacks in adopting it for your own project are clear, though: the fixed JSX renderer, abstractions hidden behind the library/transpile system, and the adaptation of <slot> into a Custom Element implementation despite its Shadow Dom origins. These framework decisions might make moving away from Stencil difficult while preserving the component design in another web component development environment.

Tweet

« Blog home