This is the first post of a series dedicated to explaining the basics about Stencil, the Web Components compiler, from the point of view of a developer with previous experience using LitElement and Polymer.
I'm one of these developers and the funny part is that I'm going to learn Stencil while I write about it. So think of it as a learning process that I'm sharing with you.
As for this first introductory post, I'm going to focus only on how Stencil is different from other approaches and why it's a good option to consider, especially for component libraries.
This is the main difference of Stencil compared to other alternatives for building Web Components and it's an important one when you're creating components that are going to be used in unknown contexts.
Even when you use a small library like LitElement, you're still in some way locked by the library. You have to make decisions about how to provide the distributable "ready to use" version of your component. Bundling the library with the component seems to be the worst option, as it binds to a particular version and limits the possibilities of optimizing the code (no deduping or tree-shaking). Requiring the library as a peer dependency or giving the consumer the responsibility of importing and bundling your components are better and more flexible solutions, but at the same time, they carry other challenges, especially for the consumer. Not to mention the risk of having components that rely on different versions, maybe not compatible, of the same library.
Stencil eliminates all of these problems by leaving the framework out for the consumer without depriving developers of the benefits of using it. In other words, your components won't need Stencil at run time to work.
Unlike LitElement, Stencil not only provides an abstraction over native Custom Element APIs and a rendering engine or templating system to make our life easier but all the goodies usually included in frameworks that improve the developer experience like a lightweight development server, testing utilities (including e2e), auto-generated documentation, and build presets.
The following features are likely to be more a matter of personal preferences, but they have also some advantages.
This can be a barrier for people not used to it and in my opinion, the worst about TypeScript is having to learn it. Apart from that, it improves the developer experience not only by providing the typings that our IDEs and editors use to offer autocompletion but mainly, and most important, by catching errors at build time that otherwise are going to appear at run time (probably in production).
Having this checking for the attributes, properties, and events of custom elements is an invaluable point that prevents errors that sometimes go unnoticed even having a good battery of tests.
This also means that you won't be able to build the component library if one component has changed its API and other components using it have not been updated accordingly.
This is probably the most controversial decision, but one more time, for the good. Stencil has chosen not to invent a new templating system but to use the one that is probably the most used due to the popularity of React. This means that a lot of people already know it, our editors understand it, and there are tools like Babel or ESLint that know how to parse it.
As far as I know, there are two approaches to distribute component libraries: including all the components in the same package or publishing them independently. The second one may appear as the best option to release versions that strictly follow SemVer and also to allow installing only the necessary. However, at least in my experience, it becomes a nightmare when different components are using different versions of shared components, more if we have into account that a custom element can only be registered once. We have to ensure that all components and the application are using the same versions of the common components and frequently this implies a lot of maintenance work.
Including all the components in the same package has also disadvantages, but at least, and thanks to the required build step, it ensures that all the components are going to be compatible between them and you'll only have to update one dependency in different places.
By this time maybe you'd be thinking that Stencil generates a huge bundle with lots of components that you're not going to use. Fortunately, it uses lazy loading to not penalize the initial load and imports only the components that are used in a page.
This is probably one of my favorite features. Web Components work by nature with any framework or library that runs in the browser, but not all the frameworks are prepared to work with them as if they were their own components. This fact can make working with Web Components less comfortable.
Stencil provides the ability to generate native framework components from a single source code. You build reusable components once and they are available for different targets.
These are my initial impressions and thoughts about Stencil but I still need to get my hands dirty with it. Hopefully, I'll have more to say in the upcoming posts.