Stencil JS

En el anterior artículo de introducción a los web components hablaba sobre el origen y las herramientas que han ido surgiendo a lo largo de los años para facilitar el desarrollo. En este artículo veremos como usar Stencil.js paso a paso, generando un proyecto desde cero usando el starter-app que proporciona la herramienta y desarrollaremos un sencillo componente contador.

 

¡Un poco de historia!

 

Stencil JS es una herramienta de los creadores de Ionic y si hay algo que esta claro es que se han inspirado en los frameworks más populares como Angular o React para coger lo mejor de ambos. Ellos mismos la definen como «El generador mágico de web components reusables».

Stencil combina los mejores conceptos de los frameworks más populares en una herramienta simple y genera componentes web basado en estándares lo que permite utilizar estos componentes sin depender de ningún framework.

  • Virtual DOM: Se realiza una copia Virtual del DOM completo o de determinados elementos, lo que permite trabajar de forma más rápida que sí modificamos y volvemos a renderizar el DOM original completo.
  • Reactive data-binding: Los componentes se actualizan cuando sus atributos o estados cambian.
  • Renderización Async: Permite actualizar componentes de la aplicación de forma asíncrona, basado en la arquitectura de React fiber.
  • TypeScript: Superset de JavaScript.
  • JSX ( JavaScriptXML): Usado como motor de plantillas para la renderización del código HTML.
  • Live Reloads. Refresco de la aplicación cuando se ha realizado algún cambio en los archivos en tiempo de desarrollo.

Vamos a ver mas en detalle como funciona el Virtual DOM y como consigue esa mejora de rendimiento.

Si has trabajado con React o has escuchado algo de esta librería te sonará el termino ya que es uno de sus principales conceptos y la razón que le permite tener un gran rendimiento a la hora de actualizar el DOM.

 

Virtual DOM

 

El Virtual DOM es una representación en memoria del DOM real que actúa de intermediario entre el estado de la aplicación y el DOM de la interfaz gráfica que visualiza el usuario.

Cada vez que se produce un cambio o se añade un nuevo elemento se genera un nuevo Virtual DOM con el árbol resultante. Como este DOM es virtual la interfaz gráfica no se actualiza, se compara el DOM real con el DOM virtual con el propósito de calcular la forma más optima de realizar estos cambios y de esta forma reducir el coste en términos de rendimiento a la hora de actualizar el DOM.

Se puede ver de una forma simple en este gráfico:

 

 

Empezando un proyecto desde cero

 

Ejecutamos el siguiente comando en el terminal y seleccionamos entre las tres opciones, en nuestro caso elegimos “app” ya que queremos generar una web entera.

npm init stencil
? Pick a starter › - Use arrow-keys. Return to submit.

❯  ionic-pwa     Everything you need to build fast, production ready PWAs
   app           Minimal starter for building a Stencil app or website
   component     Collection of web components that can be used anywhere

Dando como resultado la siguiente estructura:

 

 

En nuestro caso solo vamos a prestar atención a la carpeta components que es lo que nos interesa en este artículo.

 

Además del starter-app los creadores de Stencil nos proporcionan un CLI muy completo que nos ayuda también a generar los componentes de una manera muy sencilla y rápida, para hacerlo solo tenemos que ejecutar el siguiente comando en el terminal.

 

npm run generate

 

Nos preguntará el nombre del componente y que archivos queremos generar junto al componente (estilos, test unitario y test end to end).

 

 

Una vez creado el proyecto vamos a comprobar que todo funciona correctamente ejecutando estos comandos en orden:

 

Si todo ha ido bien nos abrirá en el navegador la página y tendremos que ver lo siguiente

  • npm install : Para instalar las dependencias
  • npm start: Sirve para arrancar nuestro servidor en modo desarrollo

 

 

¡Ya tenemos todo listo, vamos con el código de nuestro componente!

 

En los primeros pasos del artículo hemos creado un proyecto web y también nuestro componente “test-component” donde vamos a hacer todo el desarrollo.

El componente de ejemplo que vamos a crear consta de lo siguiente:

  • Title: Parámetro que recibe por la URL y muestra como titulo
  • Contador: Variable interna que mostrará el valor del contador y será modificado por botones

Antes de empezara desarrollar el componente vamos a modificar el código para que cuando pulsemos el botón de “Profile page” cargue el nuestro. Para ello tenemos que irnos al archivo “app-root.tsx” y añadir nuestro componente, quedando como se muestra en la código inferior.

<main>
    <stencil-router>
        <stencil-route-switch scrollTopOffset={0}>
        <stencil-route url='/' component='app-home' exact={true} />
        <stencil-route url='/profile/:name' component='app-profile' />
        <stencil-route url='/test' component='test-component' />
        </stencil-route-switch>
      </stencil-router>
</main>

Aprovechamos también que hemos añadido nuestro componente y modificamos el nombre del botón “Profile page” por el que queramos en el archivo “app-home.tsx”. El siguiente paso es indicar en el router que vamos a pasar una variable por URL al componente, quedando el código así:

<main>
    <stencil-router>
        <stencil-route-switch scrollTopOffset={0}>
        <stencil-route url='/' component='app-home' exact={true} />
        <stencil-route url='/profile/:name' component='app-profile' />
        <stencil-route url='/test/:title' component='test-component' />
        </stencil-route-switch>
      </stencil-router>
</main>

Una vez añadido el componente al router y modificado el nombre del botón ya podemos pasar al código del componente, donde debemos procesar ese valor pasado por la URL y agregar la variable interna del contador con la lógica interna.

Para no alargar demasiado el artículo muestro el resultado del código terminado y vamos viendo paso a paso lo que hemos necesitado añadir.

    import { Component, h, Prop, State } from '@stencil/core';
@Component({
  tag: 'test-component',
  styleUrl: 'test-component.css',
  shadow: true
})
export class TestComponent {
  @Prop() match: any;
  @State() counter;

  componentWillLoad() {
    this.counter = 0;
  }
  render() {
    return (
      <div class="container">
        <div class="center">
          <h1>¡Hola {this.match.params.title}</h1>
          <p>{this.counter}</p>
          <div class="buttons">
            <button class="button-left" onClick={() => this.increase()}>Sumar</button>
            <button class="button-right" onClick={() => this.reset()}>Reiniciar</button>
          </div>
        </div>
      </div>
    );
  }

  increase() {this.counter += 1;  }
  reset() { this.counter = 0;  }
}


Como podemos ver en el código hemos agregado lo siguiente:

  • @Prop match: Crea una propiedad en el componente
  • @State counter: Variable local que debe ser observado durante la detección de algún cambio
  • componentWillLoad: Función que se llama una única vez después de añadir el componente al DOM.
  • increase(): Función que incrementa el valor de la variable local counter
  • reset(): Función que resetea la variable counter a 0

Si nos fijamos en la parte HTML podemos ver que hemos añadido el siguiente código para mostrar el valor recibido por parámetro y para mostrar el valor del contador.

<h1>¡Hola {this.match.params.title}</h1>
<p>{this.counter}</p>

Con esto tenemos terminado nuestro pequeño componente contador que aplicando un poco de código CSS quedaría así:

 

Conclusión

 

Como hemos podido comprobar crear un componente en Stencil es realmente sencillo y rápido, y más si tenemos en cuenta que usando el CLI proporcionado nos facilita la creación en simples pasos.

Aunque el componente que hemos creado es sencillo, es suficiente para tener una aproximación a las posibilidades que nos brindan los web components, teniendo siempre en mente siempre la compatibilidad con todos los navegadores -incluso con los antiguos usando polyfills- y no depender de ninguna librería.

Espero que este pequeño artículo os haya picado la curiosidad de investigar e indagar más en esta gran herramienta y que en