How I created SmileToUnlock with StencilJS

A week ago in a flourish of creativity I madew my first web component smiletounlock.com, want to give away free content on your site? How about asking for a smile in return 😁.
Just released my first web component! https://t.co/7zwbPknbTG built using @stenciljs. Want to give away free content on your site? How about asking for a smile in return 😁 (powered by the @Azure Emotive API) — https://t.co/6MdAZ8oL4J pic.twitter.com/7mvSjs9W4O
— Asim Hussain (@jawache) October 2, 2017
In this article I’ll break down how I created it, answering questions like:
-
What are web components?
-
What is StencilJS?
-
How to build web components using StencilJS?
-
How to use advanced AI APIs like Emotive Services from Azure.
How to use smile to unlock?
Simply drop a script tag in your HTML file like so:
<script src="https://unpkg.com/
and then add some HTML to you file like so:
<
Now those of you who have been working on a modern JS frameowrk like React, Angular or Vue will recognise the above pattern.
We’ve added a piece of HTML, a custom tag called smile-to-unlock
. This is a component that encapsulates all the display and behaviour of our smile to unlock widget.
But we never included React, Angular or Vue.
The first rule of web components is that they don’t rely on any framework, they are part of the HTML spec and browsers are slowly starting to support them. Chrome and Safari support them natively most other browsers support them with a polyfill.
Web components allow you to create your own elements outside of any framework, so they work with every framework! You can use smile to unlock anywhere, Angular, Vue, React, Wordpress it doesn’t matter it works at the browser level.
So what’s StencilJS?
You can create web components natively in the browser, without needing to include any other script file, they just work. But there are frameworks out there that help you in creating web components, the most famous is polymer.
They handle things like boiler plate code, handling the pollyfills for other browsers etc…
StencilJS is the new kid on the block but it differs from the others in that it’s not a framework, it’s a build tool.
The output of stenciljs is just raw native web component code, you don’t need to include the stencilyjs library to run stencil js generated webcomponents. You just need stenciljs to buld web components, the output of the biuild process is a native web component you can use whereever.
Think of StencilJS as gulp for web components.
It’s made by the ionic team, the people behin the mobile development framework Ionic. Historically Ionic has been built using Angular but with the advent of PWAs they needed something ligherweigt, something that can let there users build mobile optimised sites which load super fast. Web componenents are the answer.
It’s currently in beta but the ionic team is dogfooding it at the moment, they are building Ionic 4 using StencilJS and the tool is improveing daily.
How to use StencilJS?
To begin with lets create a stenciljs project
git clone https://github.com/ionic-team/stencil-app-starter my-app cd my-app git remote rm origin npm install
This creates a folder called my-app
and inside there you will find your stencil project.
The npm package.json file has some scripts you can run which help with development, the first is
npm run dev
This start the local build tool running, watches files for changes and opens up the browser.
Note
When you are ready to release you can run npm run build
, this creates a dist
folder with the web component compiled into a distributable package.
Your first StencilJS component
We write stencil components is a special dialect of Typescript called tsx
JSX is an extension to the Javascript specification, you can find details here: https://facebook.github.io/jsx/, it allows you to write HTML inside your Javascript files. TSX is the typescript implementation of JSX https://www.typescriptlang.org/docs/handbook/jsx.html , so you can write HTML inside Typescript files. This allows us to use jsx syntax, the part of the code bellow that looks like we have HTML in Javascript)
A basic StencilJS component might look like so:
import { Component, Prop } from '@stencil/core'; (1) @Component({ (2) tag: 'simple' (3) }) export class Simple { render() { (4) return ( <p> Simple </p> ); } }
1 | We include the required entities from '@stencil/core' |
2 | We decorate an ES6 class with the @Component decorator. |
3 | We specify the custom tag that this class is to be assocaited with. |
4 | We have a render function where we return a p tag with the word Simple using the special JSX syntax. |
So the react developers out there will be used to concepts like JSX and the render function, the Angular developers out there will be used to the idea of decorating classes with something like a @Component decorator. Again, Stencil is not using Angular or React, it’s just borrowing ideas from both frameworks.
StencilJS feels like the best parts of React and Angular merged together.
Questions
How do you call the render function?
If you have a state variable called say foo
, how do you render the value of foo
?
import { Component } from '@stencil/core'; @Component({ tag: 'simple' }) export class Simple { foo: number; (1) constructor() { this.foo = 10' (2) } render() { return ( <p> {this.foo} (3) </p> ); } }
1 | Define a property on our class which we want to hold some state. |
2 | We set a value to our foo property. |
3 | We set a value to our foo property. |
When the foo variable changes we will want to call the render function to update our UI.
import { Component } from '@stencil/core'; @Component({ tag: 'simple' }) export class Simple { foo: number; constructor() { setInterval(() => { this.foo += 1; (1) this.render(); (2) }, 1000) } render() { return ( <p> {this.foo} </p> ); } }
1 | We increment the value of foo by 1 every second. |
2 | Then we call the render function manually to update the UI. |
To save you from having to manually call render
each time StencilJS comes with a helpful @State
decorator which you can use like so:
import { Component, State } from '@stencil/core'; @Component({ tag: 'simple' }) export class Simple { @State() foo: number; (1) constructor() { setInterval(() => { this.foo += 1; (2) }, 1000) } render() { return ( <p> {this.foo} </p> ); } }
1 | We decorate our foo property with @State . |
2 | Now every time foo changes the render function is called automatically. |
When we want to update the UI we call the render function, we can do this manually
To render the HTML above we need to call the render()
function
Simple typescript es6 classes with decorators @Component takes a tag name Render returns JSX Show a simple hello world stylus component Use by NPM RUN Consume buy NPM BUILD Questions? How do you call the render function? You can call it manually But you can also use @State variables Anytime the state changes a REF the render function si called How do you pass params in? We decorate a varible with the @Props keyword How do you call a method on the component? We decorate a function with @Method
Chrome and Safari and are coming to both Edge and Firefox. Stencil uses a dynamic loader to load the custom elements polyfill only on browsers that need it. With this polyfill Stencil’s browser support is Chrome (and all chrome based browsers), Safari, Firefox, Edge, and IE11.
First look at stenciljs What are webcomponents? Why web components? Show that you can just drop things in DRY JQuery+ Not a framework, smaller, replaces a jquery plugin Where are we with webcomponents? Browser support What is stenciljs Built by the ionic team it is going to be the power behind ionic 4 Its a compiler not a framework Polyfils webcomponents so they can be used in edge etc... How does stylus work Simple typescript es6 classes with decorators @Component takes a tag name Render returns JSX Show a simple hello world stylus component Use by NPM RUN Consume buy NPM BUILD Questions? How do you call the render function? You can call it manually But you can also use @State variables Anytime the state changes a REF the render function si called How do you pass params in? We decorate a varible with the @Props keyword How do you call a method on the component? We decorate a function with @Method How i built smile to unlock First off how did I detect a smile? I used the Azure Emotive API It's an API from the Azure Cognitive Services Suite If you give it a picture (video is being decommissioned) then for each face in the picture it will return you an object with values from 0 -> 1 for each emotion It's free for the first 30K calls (yes I said 30K!) and to signup you just go here: LINK Ok so how to build a basic smile to unlick We need to grab the users video That's all good with HTML5 and the video tag Explain the code that shows the video User has to agree Explain how to get a picture as a PNG Then expain how we send it to the API to get a value Then explain how we send an event to the outside End basic mechanism Advanced To make things easier for others (and me!) i made a second smile to unlock component which takes up the full witdth and height of the components it is used with Issues Styling It doesn't use shadow dom Shadow dom is a namespaced environmnet, almost like an iframe in that anything in that shadow dom doesn't leak out into the outside world and outside stuff doesn't leak in That makes it perfect for single use drop in componentns But if you are creating a framework of webcomponents like ionic is, then it doesnt' make sense to isolae each component, they all want to share the same stylesheet In future versions the shadow dom can be configured Concliustion Once we have shadow dom support I think stenciljs will be an amaxzing additon to the ecosistem we have right now We can create single shot components wih ease, pollyfilled with suppport for other browsers With decorators it brings up thoughts of Angular but then with JSX and the render function it then feels like react Without shadow dom support the css leaks in and out So a component like smile to unlock is hard to style fully, outside styles might leak in So right now it's better for use with single shot components that don't need styling, just render HTML and let exteral styles leak in Interested to see where this goes in the future, excited to see what happens when shadow dom is released