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 😁.

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/smile-to[email protected]/dist/smiletounlock.js"></script>

and then add some HTML to you file like so:

<smile-to-unlock api-key="<YOUR_API_KEY_HERE>"></smile-to-unlock>

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

Remember StencilJS is a build tool, we write our components in tsx files and stencil compiles them down into native web components.

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