JavaScript frameworks have become an integral part of our web development toolkit. The world of JavaScript frameworks has grown bigger and more complex. However as of today we see a phew major players like React, Angular and Vue cementing their place in the industry. All of these are powerful complex technologies with a steep learning curve. Committing to either of the frameworks creates a major dependency for your organisation and a requirement for a specialised work force capable of efficiently using the framework of choice. In addition going with one of these frameworks locks you in the Frameworks ecosystem making it more challenging to take advantage of developments in other JavaScript environments. As we know, the world of web development is an ever changing environment and committing to a certain technology without a backup plan can have serious implications for the future.
Today I would like to explore with you one possible solution for how we can introduce a "backup plan" for "safeguarding" the future of our Frontend code and potentially take advantage of developments across different ecosystems. This potential Solution is to build Web Components using our chosen JavaScript framework. Lets explore some of the options that we have today for the 3 top JS frameworks.
First lets look at what are web components and why, as responsible web development professionals, we should be interested in them.
Web Components are a collection of different technologies allowing web developers to create reusable HTML\JavaScript components with their functionality completely separated from the application that uses them. Very importantly Web Component technologies are standardized technologies for building reusable custom components thus paving a way for creating framework and browser agnostic custom components for the web.
Web components encapsulate the following 4 technologies:
One of the reasons most of us got excited with using JS frameworks such as Angular and React is the ability to split our application into simple reusable components. Web components promise to give us the ability to do this natively without worrying about third party dependencies, framework feature deprecation or employee specific skills. Web components allow to wrap UI components into isolated bits of UI logic via Custom Elements with Shadow DOM technologies and HTML templates making it possible to safely mix and match different component libraries. This opens tons of possibilities for expanding your audience when you want to share your work and significantly reduces complexity for implementing your work by other people. Finally web components are native technologies that don't require third party dependencies which should help in reducing your JavaScript library footprint and improve performance of complex UI components.
As of today Chrome, Opera, Firefox, Safar and Edge fully support web components.
Source: webcomponents.org
Most of the browser support limitations can be overcome with poly-fills on which we have to rely anyway when using React, Angular or Vue with older browsers.
There are a number of limitations with using pure web components.
As we know from the past, Web Standards can be slow to adopt. This might introduce a delay in development of new features in this space.
The variation in browser support has significantly improved and today, if you are building components for "Evergreen" browsers, you don't even need to think about it. However if you are building applications for the enterprise, which might still need to support older versions of IE, you should carefully analyse the browser support limitations that you might have to face.
The API is still quite verbose and might be hard to grasp.
Building Web components using Vanilla JavaScript can be hard but it could be a positive side effect as it could help "Framework Developers" get back to JavaScript roots and write more conscientious and performant code.
The good news is that all of the three JavaScript framework Titans have support for using web components out of the box.
In React you can directly use web components in your jsx templates
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello <x-search>{this.props.name}</x-search>!
</div>
);
}
}
Source: React Docs
In Vue you can use web components by adding them to the ignored elements list (https:\alligator.io\vuejs\vue-integrate-web-components)
Vue.config.ignoredElements = ["x-ticking-paragraph"];
In Angular you can use web components by enabling support for the CUSTOM_ELEMENT_SCHEMA (https:\alligator.io\angular\using-custom-elements)
@NgModule({
declarations: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [BrowserModule, FormsModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
Now that we know that we can safely use web components in our existing single page applications it is time to figure out how to build them with a minimal impact to our time and efficiency. This is where I have discovered that we can actually use our favorite framework to build Web Components.
The example component is a simple "likes counter" with 2 buttons "Like" to bring the likes counter up and "Dislike" to bring the likes counter down
First lets have a quick look at how to build this simple Web Component natively. I have used stackblitz to demonstrate how to do it. You can follow the code or check this Mozilla article for step by step instructions
Embed the following here https://stackblitz.com/edit/web-components-article-js?file=index.html
In the next part we will look at how to build web components with react, Angular and Vue
Next lets build the above component using React.
https://stackblitz.com/edit/web-components-article-react?embed=1&file=VoteCounter.js
As you can see nothing special here, we are extending the React.Component class, adding local state to store the "totalCount" value and adding like and dislike methods to handle the buttons functionality. All then gets rendered using the render function. We then have an App Component that renders our VoteCounter component
Things get a bit more complex when it comes to wrapping React component as a web component. React does not have a native way of wrapping React Components as Web Components. I have only found one library that claims to be capable of doing it. The library is called react-web-component developed by spring-media. Here is how you would convert the above component into a web component using this library:
install the react-web-component package
npm install react-web-component
Now create a React component using the code from the previous stages Import the react-web-components library Add some web component specific life-cycle hooks Wrap the component using the method from the React web components library Now we need to build this component as a standalone JS file Ado the build steps
This library did indeed create a webcomponent but I have hit some big limitations, one of them not being able to pass props from HTML to the react component. There are multiple issues reported on this problem #123, #234, #456. Unfortunately the library does not seem to be actively maintained and these issues have been open for quite a while now.
Another approach to use web components with React is to actually use React inside the web component. This will require React to be loaded alongside the web component.
Vue supported the concept of converting Vue components into native Web Components for a while and the process is relatively straight forward.
Vue has a native library called @vue/web-component-wrapper. The library requires vue cli V3:
vue create web-component-article-vue
src/components/RsvpCounter.vue
@vue/web-component-wrapper
library in the main.js file to wrap the component as a webcomponentvue-cli-service build --target wc
Note: for the last step I have added a dedicated main.wc.js file containing just the code required for the web component and I have added the command was an npm script Note: When running the web component in dev mode styles for the wrapped web component will not work. Everything works fine after building the web component
https://vuejsdevelopers.com/2018/05/21/vue-js-web-component/ .........
Angular version 6 has introduced a way to build web components using the @angular\elements package. Later versions of Angular introduced further improvements to @angular\elements. Here is how you would build a web component in Angular 8
This is how we would build the above component using @angular/elements
Setup a new project ng new angular-app
Generate a new component ng g c RsvpCounter
Add the @angular/elements library ng add @angular/elements
Add the @webcomponents/webcomponentsjs library npm install @webcomponents/webcomponentsjs
Wrap the Angular component as a webcomponent in the AppModule constructor
export class AppModule {
constructor(injector: Injector) {
const custom = createCustomElement(HelloWorldComponent, {injector: injector});
}
}
Now add the web component to custom elements
customElements.define("app-hello-world", custom);
Similar to the customElements issue in using react in web components, you might require a polyfill for custom elements to work.
@webcomponents/webcomponentsjs`
Simply add the polyfill to your polyfils.ts file
import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js';`
The above steps will make the component usable in Angular components allowing things like dynamically injecting the component using vanilla JavaScript.
Now lets look at how to package our component as a a standalone web component.
First lets add a new module that will only contain our web component
[Example code required]
Now lets add a new config to angular-json for building this new module
[Example code required]
Now lets add a build command that will perform the following:
ng build angular-app --prod --output-hashing=none --main=helloworld.wc.module.ts && cat dist/angular-app/runtime.js dist/angular-app/polyfills.js dist/angular-app/scripts.js dist/angular-app/main.js > preview/angularapp.js
Note:
For windows users there is a node implementation of cat
nodecat.
Alternatively you could also use this package ngx-build-plusngx-build-plus that extends the Angular CLI and provides a mechanism for outputting single js bundles
..
The Angular team has been doing a lot of work in further improving efficiency, and the bundle size produced by the Angular rendering engine to a point where a hello world App now builds to a bundle that is only 27KB in size. But the most exciting feature is the new version of Angular rendering engine code named Ivy. It has been introduced as an optin feature in Angular 8. The engine has been refactored to leverage full use of tree shaking techniques making it possible to only include the bare necessary parts of your application down to a rendering instruction level. This makes the final bundle even smaller giving even more room for producing standalone web components using Angular.
As we can see all the three JavaScript framework giants support Web Components one way or another, it is clear that Vue and Angular see it as an integral peace that will help the frameworks stand the course of time. Vue had good web component support since version 3 of the Vue CLI and has the most straightforward and easy to use tooling. The Angular team has been putting a lot of efforts into this area as well and significantly reduced the configuration required for building web components. React can easily consume web components but is not really fit for building them. It seems that the React community does not feel like web components are important to them so i don't think we will get native like support any time soon.
Who knows maybe one day all of the components we will be building will be web components. So why not start experimenting now and have one more skill in our portfolio for helping us deal with the ever changing web development landscape.