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.
Stencil is three things:
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.
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.
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:
@Propdecorator specifies properties, reflected to attributes, that are immutable component code internally.
@Statedecorator enables a component to have internal state that cannot be changed directly by a user. A change in state results in the render function being called.
@Methoddecorator identifies public API methods
@Elementdecorator is how to get access to the host element within the class instance. This returns an instance of an
HTMLElement, so standard DOM methods/events can be used here.
@Listenset up native DOM events and event handlers
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.
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:
In a Stencil application, a published and npm-installed component package can
be accessed through the application’s
where the components to be “imported” are added to the collections key. It’s
import is supported.
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
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