Sharing Data and Services
If you are used to frameworks like Angular, React, or Vue, you know how to share data and services between your components, right? In Angular, you can utilize its built-in dependency injection, in React, you can use Redux and so on. You need a new service calling some API? No problem, just create a new class, put it into DI, inject a configuration object with the necessary URLs and you are good to go to use that class in every component. Those approaches are perfectly fine because your whole application is in the hands of the framework.
If you develop enterprise-like applications, you have a lot of data to share with your components. For example, API URLs, translations, number formats, date formats, color themes or global settings. Maybe there is also the possibility for changing some of these at run time.
When it comes to Web Components, you usually live in the world of your component. Is that really true? We may need to divide Web Components into two categories.
Self-Contained Web Components
Component-Library Web Components
Another approach comes to my mind if you are building a Web Component library. Within the library, I would expect that there are some common services or configuration objects that every Web Component expects to exist. This approach can also be application-wide, so it may feel like one of the current framework’s components. It simplifies handling common and shared services and data tremendously. For example, if the user selects another language, and you have to re-translate your components, you can raise an event for that. Every component will follow that event and get the new translations from a service. With that approach, you can easily build base classes to handle such common features.
When developing Web Components, you need to start thinking much more about your data flows. Using SPA frameworks, they already have a ready-to-use solution for you. In the end, it may be a mix of both Web Component categories in each application, especially if you use third-party Web Components.
If you have other ideas, let me know!
Creating Web Components with Frameworks
Working with Web Components without any framework, sometimes feels like going back (to the future) in time. Why? Currently, we are used to have frameworks like Angular, React, or Vue that provide certain features like a template engine, dependency injection, or a virtual DOM. For native Web Components, we do not have that, so we will find ourselves adding and removing event handlers and updating our DOM manually. Like we did many years ago!
Now imagine a world, in which Web Components are built with big frameworks, like Angular or React. Speaking of Angular, even in its current form (with Ivy), a small Web Component will be around 1 MB big. Yes, there are tweets that your application is only 6 kb in size with Ivy, which is a “Hello World” application. If you include a form, your file size will increase significantly. As you may know, your application will not be built by a single component, but maybe 10, 30 or even 50. If each components size is 1 MB, you would have to download 50 MB, which is way too much for an application.
A possible solution is not to use a framework at all. That may work for smaller Web Components or smaller applications. However, for bigger applications, that is simply not suitable.
The next step would be to create your own framework instead of relying on others. If you plan to create a component library for your own applications, that may be a valid option. For sure, it comes at costs of creating the core foundation of the framework, creating your own build pipeline, and so on. You have to consider many things from the third article about the flaws of Web Components.
Additionally, if you share one framework across the entire application, all Web Components have to use the same version. Upgrading the framework can be a long process, because you have to ensure, all Web Components are working correctly.
If you want to use one of the current frameworks, it might be helpful to have a look at the following little overview of their capabilities.
Please bear with me, that this overview contains only the frameworks, I have used for Palaver. The following section only describes the creation of Web Components with the frameworks, not the usage. Using Web Components in each framework worked like a charm, and there is already enough documentation available to get started.
Stencil.js is a framework designed for development of Web Components. It features a build pipeline, creation of documentation, data handling, and event raising with JSX, you have a comfortable way of creating templates. Also, Stencil.js helps you update your DOM, whenever the state of your component changed.
Stencil.js, for me, is a good foundation to use for your own Web Components. As their website states, it is a toolchain for building reusable, scalable Design Systems. It is not an entire application framework. If you need Form Validation or Dependency Injection, you have to build that yourself on top of Stencil.js.
LitElement is from Google’s Polymer project and helps to define Web Components. It is currently more syntactic sugar and solving problems within Web Components, for example attributes and properties synchronization or templating. You will not get a build pipeline or something similar and have to rely on existing bundlers like Webpack or ParcelJS.
Depending on your need, LitElement offers you everything to create very lightweight Web Components.
Vue.js has it’s own wrapper @vue/web-component-wrapper which helps to wrap Vue.js components into Web Components. You have the whole feature set of Vue.js available. The wrapper also takes care of building your components and tells you how to write CSS for encapsulations. Additionally, it has some nice building flags to include or not include Vue.js in the resulting components. That helps with decreasing the bundle size of your Web Components.
Angular Elements wraps your normal Angular components into Web Components. It integrates nicely with the Angular CLI, so basically, you have the whole Angular ecosystem available. Thanks to Ivy, the bundle size starts to decrease. If you rely on the
OnPush change detection strategy, you can even remove
zone.js to decrease the bundle size even more!
In my view, both Stencil.js and Angular Elements have the best toolchain and support for creating Web Components. In the end, when using Angular Elements, there is not much to care about, it works pretty well out of the box. However, as mentioned in the third article about the flaws of Web Components, they lack type definitions when it comes to the usage of Web Components, even when built with Angular.
A Little Angular Note
Since I am an Angular developer, I want to make a little side note. If you want to consume Web Components, you need to add the
CUSTOM_ELEMENTS_SCHEMA. With that enabled, a lot of compiler checks for unknown properties on elements are disabled. That could lead to misbehavior of your application. I highly recommend creating an Angular module, which only wraps your Web Components and use
CUSTOM_ELEMENTS_SCHEMA in there, so the other parts of your application are not affected by it. Like I have done with Palaver.
React lovers, I am sorry to tell you, but React itself does not offer anything to create Web Components. There are community projects trying to solve the problem. However, if you compare them to the other frameworks mentioned, they need more time to mature. In the meantime, I would suggest taking a look at Stencil.js.
While it is possible to create Web Components without any framework, in a real-world scenario, it is very unlikely to do so. Frameworks help to have a good foundation for your development. If you are not satisfied with one of the existing frameworks, it is very easy to build your own. With the help of bundlers like webpack or ParcelJS its a breeze to create a toolchain.
However, if you hop on the train, you also have to address the current flaws of Web Components. Also, do not underestimate a good toolchain, which crunches your referenced assets.
For me, Web Components have one big advantage: you have to craft your component’s API carefully. Not only in terms of attributes and properties but also your CSS variables, CSS Shadow Parts, content projection and events. That strengthens your API, and hopefully leads to smaller, very specific components.