June 6, 2019
  • All
  • Announcements
  • Stencil
  • Design Systems
  • stencil

Introducing Stencil One

Adam Bradley

Today I am thrilled to announce the 1.0.0 release of Stencil—or what we’re calling “Stencil One.” 🎉

Last week at JSConf EU, we had the pleasure of announcing the Stencil One final release on stage, just a few weeks after we released the beta. Now I’m excited to go in-depth and explain what this moment means for Stencil and Ionic.

Stencil’s creation is the direct result of years spent working on Ionic, developing a reusable UI component library for millions of developers and applications, and the many lessons learned along the way. So let’s dig into Stencil’s origin story, and where we’re going next.

First, The Problem ☝️

The story of Stencil starts with a very specific problem. The Ionic team wanted to make it easy for anybody to use our component library, whether they preferred Angular, React, Vue, or some other framework. But at the time, Ionic components were only compatible with Angular.

In our quest for universal compatibility, it occurred to us that, as far as the framework logic is concerned, an <ion-button> element is no different than a <button>. Both are just elements in the DOM, and in both cases, the developer is able to interact with elements using properties, attributes, and events.

When we accept that <ion-button> is no different than any other element on the page, it immediately expands our universe of possibilities. The low-level framework actually doesn’t matter. In fact, without a dependency on any specific framework, using an Ionic component can be as simple as:

const btn = document.createElement('ion-button');
btn.textContext = 'Hello Ionic';

This gave us enough to believe that Ionic could, in fact, decouple itself from unnecessary requirements, dependencies, and direct ties to a specific framework, or framework version — but not without some help, as you’ll see later.

Enter Web Components 🧩

The first step in our journey, then, was to move our component library to Web Components instead. More specifically, Custom Elements.

Web Components allow Ionic to use web-standard APIs already built into all modern web browsers, rather than framework-specific APIs that are version-restricted and may change over time. Essentially, this enables Ionic components to be created and connected to the DOM, no different than any other element.

The Second Problem 🤔

However, Web Components have purposely been designed as a very low-level web API, and as they scale and become more complex, things start to get a little trickier. Common scenarios include growing application complexity, team members moving on and off the project, business requirements changing, and creeping tech debt.

The complexity of maintaining apps can quickly escalate, which in my opinion is why frameworks such as React, Vue, and Angular have become so popular. They solve a real problem. Frameworks are the glue for components and are able to provide a common structure and best practices to help teams develop and maintain large applications.

So, while we saw the immense value of porting our components to Web Components in order to become framework agnostic, we immediately realized that in doing so we would lose out on all the great features and developer experience that come with frameworks. The questions quickly piled up:

How would we…

  • Setup a dev server that’s integrated with watching the file system?
  • Perform Hot Module Replacement or reload styles on file changes?
  • Prerender components in each framework?
  • Run unit and end-to-end tests?
  • Integrate these components in React, Vue, Angular, etc.?
  • Export component types for frameworks, JSX and HTML?
  • Document component properties, attributes, events, CSS variables, etc.?
  • Set up differential bundling for modern and legacy browsers?
  • Efficiently bundle modules using modern ESM standards?
  • Minify ES2017 builds and separately minify ES5 legacy builds?
  • Print error messages pointing directly to the source?
  • Precompile Sass and minify CSS?
  • Configure the package entry points for ESM, CommonJS, and CDNs?
  • Set up linting rules?
  • Take screenshots and perform image comparisons against the last commit?

The list above only scratches the surface problems that need to be solved without a framework. And by solve I mean, “figure this out entirely on our own”, because Web Components themselves do not provide any answers to the above questions. Each one is certainly doable, and there are many dependencies developers can piecemeal together.

However, the R&D time just to figure out how to answer all of the above questions with the wild west of external dependencies is a problem in itself. And not just to work on our development machines, but Ionic’s package setup must be capable of being imported by all bundlers, frameworks and external tools, which is something that’s not exactly cut-and-dried.

Enter Stencil 👋

We had to find a better way. And that’s what led us to Stencil.

Stencil is a compiler that generates standards-compliant Web Components, while also delivering the best concepts of the most popular frameworks into a simple build-time tool.

Stencil takes features such as

  • Async rendering
  • Reactive data-binding
  • TypeScript
  • JSX

and then generates standards-based Web Components with all these features baked in.

Since Stencil generates standards-compliant Web Components, we solved our original problem of making Ionic compatible with all popular frameworks right out of the box. They could even be used without a framework because they are just Web Components. And on top of that, Stencil also enabled a number of key capabilities, in particular, prerendering, and objects-as-properties (instead of just strings).

Compared to using Custom Elements directly, Stencil provides extra APIs that makes writing fast components simpler. APIs like JSX and async rendering make fast, powerful components easy to create, while still maintaining compatibility.

The developer experience is also tuned and comes with live reload and a small dev server baked into the compiler.

An Unexpected Benefit: Size & Speed ⚡️

While our journey started with a desire to build a framework-agnostic component library, Stencil delivered some incredible – and somewhat unexpected – benefits. By making Stencil a build-time tool, and using the built-in capabilities of the browser via Web Components, we found that our bundle sizes for Stencil apps were incredibly small. Like, insanely small. And the speed of our components blew away our expectations.

Since Stencil is able to statically analyze the source of every component, the compiler is able to apply heavy optimizations and only include exactly what the components require. This means smaller file sizes, which are perfect for PWAs, and extremely fast startup times. Since every Stencil build will be different, below are commonly used examples in order to have a comparison.

Hello World: 83 bytes compressed, 133 bytes uncompressed
Todo MVC: 2.0KB compressed, 4.88KB uncompressed

And these same numbers scale quite well for all of Ionic’s components!

Design Systems 🧬

One of the reasons you’re even reading this blog is that we eventually made the decision to release Stencil as its own open source (MIT) project. Up until now, we’ve talked only about what Stencil has meant for the Ionic team, but the Stencil project has taken on a life of its own. In fact, we’re always excited when we hear from teams that are passionate about Stencil, and have no clue it’s made by Ionic.

Perhaps the most popular use case for Stencil is Design Systems. Design System initiatives have attempted to centralize brand, voice, componentry, and more for decades at large enterprises. However, when attempting to distribute actual code-based components for use in any project across the company, many enterprises have failed at gaining critical adoption due to having chosen one specific framework to make components in. Write your component library in React, and you’re only helping teams that use React in your company.

These teams have started to use Stencil to build their own custom component libraries, and have found success because the components they build will now work with any framework – helping to ensure their universal adoption within the organization – while also bringing the benefits of reduced bundle sizes and increased performance to their apps. Our team has since taken this a step further by developing specific solutions to address Design Systems directly. We call this offering StencilDS, and you can learn about it here.

What’s Next: Stencil Roadmap 🗺

Ionic has been built with Stencil since Ionic v4, so in a sense, Stencil has been in production for quite some time now. Before we released version 1.0 of the Stencil compiler though, there were a few areas of Ionic Framework’s development which helped discover more areas for improvement.

Because Stencil is a compiler that can do so many powerful things, surprisingly enough one of the biggest challenges is deciding what it should not do! Keeping the API tiny and continually aligned with web-standards is extremely important to us.

Some additional goals:

  • Stability: Continue to close out bugs while avoiding breaking changes at all costs.
  • Documentation: Continue to iterate on our docs by adding new content and focusing on writing clear and concise information.
  • Demos: Build more demos showcasing best practices we’ve discovered.
  • Prerendering and SSR: Stencil One can already prerender components, but the next step is to demonstrate how they can be used in other projects such as Angular Universal, Gatsby, and Next.js.
  • Community: We’re thrilled to have such a large, vibrant and helpful community already, but will keep working to further improve the ecosystem, become more transparent with our roadmap, and keep the community up to date via Twitter, Slack and soon a dedicated new blog on Stencil’s website.

Start Building! 🛠

Hopefully, this helped explain a little bit more of Stencil’s story, and where we’re going next. If you haven’t tried out Stencil yet, we encourage you to take five minutes and toy around with it:

npm init stencil

Follow our full Getting Started guide in the docs.

Thank You ❤️

Lastly, on behalf of the whole Stencil team, I’d like to give a huge thanks to everyone in the community who has helped make Stencil One possible. Throughout this nearly two-year journey, your feedback, patience, contributions, and encouragement have helped us bring Stencil from an ambitious vision to an incredible reality.

We’re looking forward to hearing how Stencil One is working for you, and we’re excited to hear your thoughts, feedback, and questions.

Happy building! 🤙

PS… Watch the Stencil One announcement video from JSConf EU below:

Adam Bradley