Building #webcomponents (while avoiding common pitfalls) using #stencil with end-to-end #storybook integration

Building #webcomponents (while avoiding common pitfalls) using #stencil with end-to-end #storybook integration

My first interaction with webcomponents (WC) was interesting. Given that it was a long time ago, I didn't even fully appreciate the robustness of WC. To me it was just a piece of code (auto-completing different parts of address fields from a lookup address, hail Google) working as a blackbox and serving my purpose at a hobbyist level. Fast forward a few years and I can tell you this situation can escalate very quickly when you put a design system and CMS integration (and a couple of sleepless nights) into the mix (and that at enterprise level) and you will get a love-hate relationship with WC. To be fair, even then it had (has) its perks and nonetheless that is very interesting too, especially if you have someone to bounce ideas with or look for some guidance through brainstorming and most importantly keep it all sane at the same time (thanks again @Alex).

Now, if you are using a traditional framework few of the prominent and common pitfalls that come as a baggage (specially if you are building a big library) are:

  • Size of the library (hence the first loading time)
  • SSR & SEO
  • Accessibility
  • Framework defined DOM specific entry point
  • Cross Platform Compatibility

If you are still with me, then this could be a good segway to the topic of this article, StencilJS , a completely free and open source utility, they actually call it “A Web Components Compiler”. You will see how easy it is to create WCs using StencilJS along with a documentation/guide called Storybook while avoiding the above mentioned common pitfalls (well almost). Check out the Stencil FAQ page if you are still a bit hesitant to progress.

Now let's proceed (I wish LinkedIn provided a way to add colour and syntax highlighting in the snippet area and I didn't have to use screenshots).

Prerequisite

  • Make sure you have recent LTS versions of NodeJS and npm (as the documentation suggests it requires npm 6 or higher) installed. Once installed confirm the version

> npm -v
8.5.5
        

Project Initiation

  • Go to your preferred directory, open command prompt and issue the following command

> npm init stencil        

  • This will prompt the following options, select “component” from the starter project option

No alt text provided for this image

  • It will ask for the project name, give it a name (in this case let's use “bss-components” and then confirm. This will initiate the project and will give you a brief overview of what to do next.

No alt text provided for this image

  • Change directory to the newly created folder and run the install command

> cd bss-components
> npm install        
No alt text provided for this image

  • Once finished, issue “npm start” command in the command prompt. This will start the development server and

> npm start        
No alt text provided for this image

  • It will start the transpile (you can read the stackoverflow thread to know the difference between transpiling and compiling ) process and load the page

No alt text provided for this image

  • It will be shown with the component created by default and if you inspect the element you will see a custom tag called <my-component> is responsible for the display of the above text

No alt text provided for this image

> code .        

  • If you look at the folder structure you will see the component created by default is under /src/components/my-components/ folder. The file we really are interested in is my-component.tsx. Open the file

No alt text provided for this image

  • The code will look like below

No alt text provided for this image

If you look at the code, it’s pretty straightforward. We are importing related namespaces, defining the custom tag as “my-component”, for look-and-feel we are adding a css file for it (i.e. my-componentn.css) then defining three properties (i.e. first, middle and last). Using the getText() method we are formatting the output of the text (i.e. from the @Props) and finally we are rendering the component the way we want. Like I mentioned, it's really straightforward and you can read it in detail on their website. Now that we are sort-of familiar with the basic structure let’s create a very basic but our own web-component (by the way the other two .ts files that you see in the folder structure are for testing).

Let’s create our own web-component

Now let’s actually create our very own component. How about we create a custom blockquote component with properties that can be rendered like below (let's just use BootStrap blockquote as our model for the time being):

No alt text provided for this image

Feature (property/attribute) wise, basically we have Title (text), Citation (source), Alignment (alignment) to customise this <blockquote> element and the equivalent html to render this (as copied from Bootstrap documentation site)

No alt text provided for this image

Now what we want our custom WC to look like below (if you recall the properties we mentioned above)

No alt text provided for this image

and render like below

No alt text provided for this image

Let's build the component now

  • If you are already in VS Code, from the terminal issue the command “npm run generate”.

> npm run generate        

This will prompt you for the component tag name, in this case let’s use bss-blockquote, it will also ask you what extra files (i.e. css and those two test files) you want to generate. Simply select the default selection and press enter. You will see it generated a new component file titled as “bss-blockquote.tsx” with other related files under the /src/components/ folder.

No alt text provided for this image

  • Note the folder structure now looks like below

No alt text provided for this image

  • Open bss-blockquote.tsx file and modify the existing code to suit our needs

No alt text provided for this image

  • That’s pretty much it! Our component is ready to be used now. But first transpile the code by running the following command “npm run build

> npm run build        
No alt text provided for this image

  • Now let's open the index.html file under /src folder

No alt text provided for this image

  • And add our custom <bss-blockquote> tag (err webcomponent)

No alt text provided for this image

Now to see it in action we can issue the command “npm start” which after completion

> npm start        
No alt text provided for this image

  • will open a browser window with the index.html file showing the build initialising

No alt text provided for this image

  • And finally index.html will be loaded with the following content rendered

No alt text provided for this image

  • Now if you remember we have now two components on the page, the first one was the default one created by stencil itself and the second one was created by us. If you inspect you will see our component

No alt text provided for this image

So, literally in a few minutes we were able to create our first web component (well, in real life you will probably not create a blockquote component like this, but hey, you get the idea).

Let’s create something a bit more useful

Now that we’ve got some idea, let’s actually make something useful (almost like a utility but in disguise of WC) and fun

  • As it’s a new component run the command “npm run generate” give a name, in this case let’s call it bss-collection and select the default files

> npm run generate        
No alt text provided for this image

  • The idea behind this component is to consume a rest API call and then render the consumed json array into cards array. Essentially the component will look like at its simplistic pattern like below

No alt text provided for this image

  • And this will return something like

No alt text provided for this image

  • Sounds interesting? Let's build that. We have our file. Let’s open the bss-collection.tsx file and make the following changes. We want the newsitems as @State() as we want to make sure it updates whenever the value changes as well, whereas rowcount can be a property.

No alt text provided for this image

  • Now because we need to make an API call we will need to make sure when this needs to be executed. If you look at the component lifecycle method documentation of StencilJS you will see componentWillLoad() is where we need to make that api call. The code itself is self explanatory.

No alt text provided for this image

  • Now that we have the data in our array we can start rendering it

No alt text provided for this image

  • Now you can clearly see I have used some sort of card (well from Bootstrap) format css.

No alt text provided for this image

  • If we do a rebuild and add the component in the index.html

No alt text provided for this image

  • We can see the rendered page as shown below

No alt text provided for this image

  • And with a bit of more tweaking to the css we can make the news grid look a bit more interesting (with css3 transitions and what not, please note, css credit for the following card styles: https://codepen.io/tgaychey/pen/PROMVy)

No alt text provided for this image

  • Now let's extend this a bit more. Think also about adding some properties like type (e.g. news, events etc.), topic (e.g. covid-19, flood, ai etc.) or even region (e.g. act, nsw etc.) to get a subset of your api data. And then also consider cross referencing this with other sites (or applications for that matter) running in your organisation, or even better between other organisations (as long as you follow a standard api data schema). Now if you think about it, this can be really powerful if you implement it correctly, you can have a component that can simply look like below

No alt text provided for this image

  • And I can assure you the end result can be really rewarding in terms of making your content editors’ life easier. Ok enough of this, I am pretty sure you get the idea.

Avoiding some common pitfalls

In the beginning I did mention how StencilJS can overcome some common pitfalls. I am conscious about the fact that the article is getting really long, but I will quickly show you one of the biggest issues (i.e. size and initial page load hit) that can be avoided using StencilJS.

Component size issue (initial page load hit):

  • If we open the index.html

No alt text provided for this image

  • and from dev tools see the network tab we will see all three components are getting loaded (see the related js files in the gif image below).

No alt text provided for this image

  • Now if we comment out two components like below and keep only <bss-blockquote> components active we will see something interesting happening.

No alt text provided for this image

  • Because it supports lazy loading and it can load related files for the components that are in use (see only the active component’s related js file is loaded in the gif image below).

No alt text provided for this image

It’s pretty cool, hey!

Framework defined DOM specific entry point:

  • Well you already guessed it, no app, or root or specific binding.

SSR and SEO

  • From StencilJS:

The hydrate app is a Stencil output target which generates a module that can be used on a NodeJS server to hydrate HTML and implement server side rendering (SSR)“.

You can view the documentation from StencilJS. To be honest this didn't work with my scenario, but it could work for your scenario. I will come back and revisit this section.

Accessibility

  • All UI components built with Stencil are based 100% on open web standards.

Cross Platform Compatibility

  • Combining Capacitor with Stencil you can very easily make a cross platform component, in fact it comes as an out of the box feature. You can read this excellent article published on Ionic blog.

Final part: Building a documentation site for your design system (or components)

One of the key requirements while building a design system (or component libraries) is to also integrate a playground area for your end users, to build, test, and document the whole thing in isolation. Storybook has been one of the main goto options for this purpose and integrating Storybook with Stencil is simply very efficient and easy. And that is exactly what we are going to do now. We have created two components and we will see how easy it is to showcase these components in Storybook using Stencil. Ionic has published a step by step blog on this, but let's do it here together.

Add Storybook to our project

  • The very first thing we need to do is to go to our related directory and then add storybook to our project by running the following command in the terminal “npx sb init --type html”. This is going to take some time to install all the related packages.

> npx sb init --type html        
No alt text provided for this image

Once finished it will show you the following message

No alt text provided for this image

  • And as it suggests we have to run the command “npm run storybook”. Once done, this will open the browser window with its default example documentation.

> npm run storybook        
No alt text provided for this image

  • You will notice the folder structure is updated with a new .storybook folder at root and a stories folder under the src folder.

No alt text provided for this image

  • Open the preview.js file under the .storybook ?folder and add the following code

No alt text provided for this image

  • Run the following commands?

> npm run build
> npm run storybook        

Add our first story

  • Let’s add the <bss-blockquote> component to the storybook. To do so create a new file under the bss-blockquote folder as bss-blockquote.stories.ts
  • Add the following code to the bss-blockquote.stories.ts

No alt text provided for this image

  • Add template matched with the bss-blockquote.tsx file

No alt text provided for this image

  • Finally export the class

No alt text provided for this image

Once saved the Storybook should be refreshed and you should see the newly added component story on the left hand side under components.

No alt text provided for this image

  • You can now interact with the component as shown below. Notice how changing the property values changes the behaviour of the component.

No alt text provided for this image

  • Also when you click on the Docs Tab it shows you the following option. You can also click “Show code” option and copy the code

No alt text provided for this image

That’s it

And that’s it. We are at the very end of the article. In this article I tried to show how easy it is to create components (or component libraries) in Stencil while avoiding common pitfalls. There is a dedicated section in Stencil documentation that outlines about how you should tackle if you are thinking of creating a design systems with Stencil. I also tried to show how easy it is to integrate Storybook with Stencil and how rich the interaction is.

Hope this helps someone who is thinking about venturing into web components.?Until next time, happy coding!.

要查看或添加评论,请登录

Abdullah Quazi的更多文章

社区洞察

其他会员也浏览了