A Sample for Stencil Website, that can be exported as a component library also
Stencil App Starter
Stencil is a compiler for building fast web apps using Web Components.
Stencil combines the best concepts of the most popular frontend frameworks into a compile-time rather than run-time tool. Stencil takes TypeScript, JSX, a tiny virtual DOM layer, efficient one-way data binding, an asynchronous rendering pipeline (similar to React Fiber), and lazy-loading out of the box, and generates 100% standards-based Web Components that run in any browser supporting the Custom Elements v1 spec.
Stencil components are just Web Components, so they work in any major framework or with no framework at all. In many cases, Stencil can be used as a drop in replacement for traditional frontend frameworks given the capabilities now available in the browser, though using it as such is certainly not required.
Stencil also enables a number of key capabilities on top of Web Components, in particular Server Side Rendering (SSR) without the…
In the last Post I shared with you that stencil is a Web Components Compiler focused on Custom Elements which uses TSX and other reactjs inspired technology
Yesterday I decided to make some public stuff so you could see what I was talking about and I kind of took it a little further deploying a website to firebase and also publishing the same website on npm and then use the components on the website to share and use in other website/project.
Let me tell you that I was Amazed with the results, but let's get started with forms first, because that's what I promised on the last post
From those 3, tun-navbar is badly designed for sharing, because it has implicit and explicit data from the web application itself (like routes exclusively for the website itself) it's like that on semi purpose (I didn't think it was going to be easy to share at all) but it's a gotcha you can already see when working with shareable website components in stencil, you could replace those routes with slots or even properties in a way that the component isn't depending on your website at all, but allow it to be extensible.
The other two components are mere forms without a specific purpose, they exist just to show how to do stuff in stencil rather than make a website work.
In Frameworks like Vue or Aurelia I like to work with top -> down communication, and then producing events in children elements with listeners In their parents that way I can use the same component in different context as long as that context has the same properties and similar meaning.
In the case of tun-data-form we use it like this in the forms page
we're passing down a Boolean value to know if we can edit data, some websites, display information almost ready to edit but we need a click on a switch/button else where to allow us edit information, we're just following that in here.
In tun-data-form we can see quite a lot of code but let's go step by step
on the first line, we import what we will be using on our component, the following code specifies where to find our custom styles and which tag will be using for this component.
On the next line we have our class declaration and start looking at some code
we have the following decorators
Prop
Event
State
Prop is a decorator that lets us specify that the marked class property will be coming from the outside of the component
in this case, it is that edit property that we used before on forms.tsx, the difference from Prop and State is that props are by default one way binded and can't be modified by the component itself.
Event is a decorator that will allow us to send events to the exterior of the component in a way that can eventually be captured as in a usual form element.addEventListener('submitDataForm',() => {}, false)
State is a decorator that tells our component that class properties marked with this, will be used internally in the component and that they don't need to be exposed.
(for the usage of the onInput function please check the last post)
In this part we lastly use this.submitDataForm and this.resetDataForm which are the class properties we marked as @Event earlier, these are just sintactic sugar for the following
in the end We're still #UsingThePlatform just take in mind that everything on the methods, functions etc is tied to your logic and such, but the least a component depends on something, the more portable it is
now I should be able to use this form component wherever I want, if I find fit I can also pass a property which may contain everything I need to fill those fields before using it that's just up to usage
now If we go to the forms page, there will be a method with another decorator we haven't seen yet @Listen()
it may look like Stencil is declaring stuff somewhere and adding itself to window in some way but no, this is totally just javascript under the hood, just browser API's and nothing more, we're not using any kind of framework or framework specific methods, functions; It's just the browser environment with it's API's
The code here is fairly simple, it's just Listening to the submitDataForm custom event that we fired (.emit()) in the tun-data-form component as you can see, the properties we sent in our emit, now are available on our detail property of our Custom Event having these emited, we can now start doing ajax stuff, either sending it to our API, processing it somewhere, storing it on Local Storage, whatever you want/need to do with that information
Bonus
So far we have a form that doesn't depend on custom business logic, it's job is just about collecting data, and emitting that data for a parent component to manage the business logic for it. What if we decide that we have other application that should use the same component? but meh, it's on angularjs I bet it won't work.
Wrong! head to this place to see how the form is performing and how it seems to work, pleas open the console and see that we're logging what we get from our custom events we fired.
I have published the same repository in NPM with the help of these Docs
and also with the help of unpkg, and created this stackblitz where I wanted to use the forms I created for my website
(you can try that too https://unpkg.com/tun-stencil-sample@0.0.1/dist/tun-stencil-sample.js)
Now Pay attention because, this blew my mind once I realized what was going on here
in the index.html we have the following code
<divid="app"><divui-view></div><hr><h1>Don't forget to check the console</h1><tun-profile-formedit></tun-profile-form><hr><tun-data-formedit></tun-data-form></div>
those are the same forms we created in our previous website! NO MODIFICATIONS :super_ultra_crazy_mega_parrot_ever:
you will need to add/remove manually the edit property for the moment, but on the right side you can see how it is working equally to the website you visited before!
yeah but event handling must be hard right? Wrong! head to app.js and you will see at the end the following lines
whaaat? I mean just that? that means that if I'm using Aurelia I would be doing <tun-data-form submit-tun-profile.bind="myFn($event)"><tun-data-form>
If I'm using Vue it would be <tun-data-form @submit-tun-profile="myFn"><tun-data-form> and that is Just Awesome! I haven't personally tried it but hey, did you check that the template is actually using Angular Js? and let's be fair angularjs isn't the most outsider friendly framework out there and I have tested some compiled polymer web components previously in Vue and they worked just fine so I'm completely sure Stencil will work too.
My head was blown off yesterday when I was finishing doing this, it only took a couple of hours! not days, not weeks, not months, just a couple of hours for the Maximum Portability I've ever seen.
My heart has been taken by Stencil and I can not express how much interested and amazed I'm at the work of the Ionic Team that made all this work possible in a way that is not only intuitive but without that extra bunch, frameworks often put in.
Lastly I wanted to share a video from last year when they first presented Stencil at the last year's Polymer Summit 2017
Thank you for reading this mess of a post, and please share your thoughts on the comments below! also any feedback on the code I have share with you is pretty much appreciated, I'm not a heavy user of tsx/jsx so there might be some patterns that are not great at all.