Recently I went looking for ways to code web components and found this great post - “All the Ways to Make a Web Component - October 2020 Update”. It lists ~30 libraries for creating web components, comparing code style, performance and bundle size. One of the libraries got me intrigued - Stencil - which looks very promising and has lots of stars on GitHub - about 8.6k.
Stencil is a React-inspired web component library. It is using the same JSX as React and some of the same concepts (Render function, props, state). However, Stencil differs as it compiles to an optimal bundle, creating Virtual DOM that is consolidated directly into the DOM itself (no VDOM to VDOM comparison). The result is standard web components with optimal performance.
On top, Stencil provides good development experience through their template applications - for building a component, a website / app or a PWA. Stencil also supports server-side rendering and hydrations for websites that need to be optimized for indexing.
Here is an example of a TodoMVC application:
In this article we share what we’ve learned from building a TodoMVC application using Stencil.
Our finished copy of the complete Stencil TodoMVC application is on GithuB:
Here’s an equivalent React TodoMVC application for reference:
Just for the fun of it, we also added a Svelte TodoMVC application for the performance comparison
A side note on Svelte - that’s another framework we’ve considered in the past and one we’re following closely today. Our Wix Engineering podcast did a whole episode on Svelte, speaking to its creator and Wix devs. You can listen to it here and read the full podcast transcript here. Now back to Stencil.
Building a TodoMVC using Stencil
To get started building TodoMVC with Stencil, we first need to create a dev project.
Running this command asks us which type of project we want to create - we’re creating a component, so we choose “component”.
With the project created, we start working on our TodoMVC application.
First, we define the Todo component as
There are a few things similar to React, a few that are different.
The first thing we see is the @Component decorator which tells Stencil to generate a web component named `todo-app`, include a CSS file and use the shadow DOM.
Second, we see the decorators for @State, @Prop which are used to declare state and props of the component. Those decorators accept additional parameters to fine-tune the props and state declarations.
In fact, the actual Render functions are very similar - here they are side by side:
While very similar, there are still some important differences between the render functions.
First, in React access to props and states is done via this.state.newTodo and this.prop.model. With Stencil both the props and state are just members of this - this.newTodo and this.model.
The second difference is the use of the class attribute instead of the className attribute. The semantics are the same, with Stencil using the more standard naming scheme.
The third difference is event binding, where in Stencil they promote using arrow functions while React promotes explicit binding using the .bind() function. This is obviously a preference and both options can be used in both libraries.
The last, not so obvious, difference is with using child components. In the React version, we see the use of TodoFooter and TodoItem - both are React components which are imported into the module. However, with Stencil, the child components are todo-footer and todo-item, and there is no import statement to import those into the module.
While this may seem strange at first glance, it actually makes sense once you remember that both todo-footer and todo-item are web components and are supported natively by browsers.
Performance - Compared to React and Svelte
When comparing Stencil to React and Svelte in terms of performance, Stencil scores a higher lighthouse score for desktop. For mobile, Svelte takes the lead but is less stable. Stencil on mobile is close behind Svelte and is more stable.
Mobile Comparison (3 runs):
All the libraries score very high grades for the TodoMVC case. For me it was no surprise that Stencil was faster compared to React. What was a surprise is that it is also faster compared to Svelte, at least within this use case.
I have to admit that coding in Stencil was a quite delightful experience. The coding style is a bit cleaner for me with the use of decorators, the split of CSS to multiple files makes a lot of sense.
Stencil gives a great way to build web components while allowing us to keep using the standard toolset we all like - from SCSS, LESS, PostCSS, Rolloup or Stylus, to integrations with different frameworks like React, Angular, Vue, etc.
It enables creating web components, static site generation, server-side rendering with client side dehydration. It even has documentation generation for Stencil components.
Overall, Stencil is a great alternative to React and stacks well against Svelte too, which makes it a framework that’s definitely worth looking into.
This post was written by Yoav Abrahami
You can follow him on Twitter
For more engineering updates and insights: