loading...
Cover image for Building Chat Web Components with StencilJS and Ionic 4

Building Chat Web Components with StencilJS and Ionic 4

keyvan_m_sadeghi profile image Keyvan M. Sadeghi Updated on ・4 min read

Greetings to the amazing DEV community! I wanted to share with you my experience building a Web Component library using StencilJS and hear your precious feedback/comments.

Here's what I've built:

Assister Chat

Live Demo

GitHub

The Problem

First let's discuss why I chose Web Components, we've seen debates here on why one would and wouldn't use web components.

You've probably seen a lot of Chatbots popping out in various webpages. These are usually proprietary add-ons that people buy from a vendor, adding them to the page with a script that pushes an iframe to the body. Intercom and Drift seem to be popular. I was thinking about an Open Source alternative and Web Components seemed a natural fit, main reason being thatShaddowDOM prevents CSS conflicts with the host app.

Technology Choice

I struggled a lot on the choice for the right tool.

You should think long and hard about React

People either love or hate React, but the truth of the matter is that its influence is HUGE. Earlier this year, there was a long and heated discussion on MDN Docs spring planning repo about why a web standards body is using a non-standard library. David Flanagan makes a sound argument IMO that attracting contributors without using React is hard. So that's one side, contributors.

The other side is people using your components. React developers most likely will ignore your library if they can't use it within JSX in ways they're accustomed to (ref={} for example).

View vs. Logic

A simple fact about standard HTML is often times ignored, I'm guilty of this myself.

you don't see anything that's not described

<p> I've been described, therefore I am! </p>

chat-pane is an example of breaking that rule. It contains logic and shows elements (chat-input) that are not described.

I was about to do the exact same with chat-message, I thought it'd be cool for chat-message to have an attribute named meta that contains information about its author, date sent, date read, etc. so it can render the footer based on these meta data. Not cool! That's not the HTML way of of doing things.

HTML was the "View" of the web way before all these front-end frameworks. If we're creating Web Components, we should strive for expanding the HTML vocabulary with the same semantics. People mock that attributes are just strings in web components. Mock all you want! This has been an elegant design of HTML that has withstood the test of time, and decouples HTML from JS/JSON.

That said, I'm not at all against having higher level components that embed application logic. However, the place for those are inside the specific application, not the general web component that we're designing for reuse.

Ionic 4

Another choice that I made was to reuse components from Ionic. In retro, I'm happy with that choice. Ionic components may seem overwhelming at first, but you come to realize that they are not complex at all, things like ion-content and ion-item are essentially glorified divs with some useful utilities! Kudos to Ionic team's flexibility for moving to Web Components in v4. There're still quirks, for instance, ion-virtual-scroll is currently Angular-only. My guess is Ionic Components will only get better in time. Using them in Stencil was seamless, unsurprisingly, as they are both made by the same company.

StencilJS, does it have the answers?

Let's first talk about the compiler thing:

@Component({
  tag: 'chat-message',
  styleUrl: 'message.css',
  shadow: true
})
export class Message { ... }

See the name of that class, Message? What do you think will happen if I change it to JustinBieber?

Nothing!

Nothing breaks, everything still works! You know why? Because the name of this class doesn't have any semantics at all. The class doesn't extend the HTMLElement class, or any other class. It's just there for that @Component decorator to create a host of other classes from it! Namely:

HTMLChatMessageElement: generated by the compiler for natively interfacing with the element. This one does extend HTMLElement.

interface ChatMessage extends JSXBase.HTMLAttributes<HTMLChatMessageElement>: this is the beauty. Remember React users? Covered by the compiler!

I was "meh" about using TypeScript at first, but you know what? Stencil automated creation of documentation pages from the types alone. That coupled with not having to write a types.d.ts and maintaining it for the project, I think it was a win.

Conclusion

So is StencilJS the answer? IMO, hell yeah! For a specific scenario though. If you are a shorthanded dev like me, Stencil automates a lot for you. In doing so however, it falls in the framework of the framework/library category. On the other hand, the end results adhere perfectly to web standards. Do a view page source on the demo page, fills me with joy to see this is possible again.

Posted on by:

Discussion

markdown guide
 

I’ve been wanting to try StencilJS and Ionic for a while.

Now I’ve got a cool project to explore.

Thanks!

 

Glad that you found it interesting, let me know if I can be of any help!