Crea tus propios componentes para cualquier framework usando Stencil JS
Published: 2020-10-10 21:22:27

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y6zzcv8clap3wvi02v8k.png)

Uno de mis propósitos en este mundo del Frontend, es que no exista más una guerra de Frameworks, más allá de que si cada uno tiene sus desventajas y ventajas, primero debemos aprender las bases que es lo más esencial y lo más importante, en eso estamos claros.

Otro punto importante es que las empresas deben limitar su capacidad de contratación enfocadas a un framework en específico, por eso cuando las grandes empresas realizan muchos proyectos en diferentes frameworks y no se casan con alguno es un gran avance. Pero con ello viene otro problema y es que cuando toman esta decisión encuentran que les toca rehacer el mismo código para cada proyecto, sobre todo cuando hablamos de componentes.

#### Los webcomponents llegaron al rescate


### WebComponents

Los webcomponents son bloques de código que encapsulan la estructura interna de elementos HTML, incluyendo CSS y JavaScript, permitiendo así que el código se pueda volver a usar como se quiera en otras webs y aplicaciones
Consiste en tres tecnologías principalmente, las que se pueden usar juntas para crear elementos personalizables versátiles que encapsulan la funcionalidad y pueda ser reutilizada donde sea sin miedo a colisiones de código.

* Custom elements (elementos personalizados):
* Shadow DOM
* HTML templates

Hay muchas librerías para crear Webcomponents, inclusive se puede crear webcomponents con Vanilla.. 

Vamos a crear este contador como Webcomponent

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7yd0jmz5vct2ffcya9sf.PNG)

```javascript
const template = document.createElement("template");
template.innerHTML = `
  <style>
    * {
      font-size: 200%;
    }

    span {
      width: 4rem;
      display: inline-block;
      text-align: center;
    }

    button {
      width: 4rem;
      height: 4rem;
      border: none;
      border-radius: 10px;
      background-color: seagreen;
      color: white;
    }
  </style>
  <button id="dec">-</button>
  <span id="count"></span>
  <button id="inc">+</button>`;

class MyCounter extends HTMLElement {
  constructor() {
    super();
    this.count = 0;
    this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    this.shadowRoot.appendChild(template.content.cloneNode(true));
    this.shadowRoot.getElementById("inc").onclick = () => this.inc();
    this.shadowRoot.getElementById("dec").onclick = () => this.dec();
    this.update(this.count);
  }

  inc() {
    this.update(++this.count);
  }

  dec() {
    this.update(--this.count);
  }

  update(count) {
    this.shadowRoot.getElementById("count").innerHTML = count;
  }
}

customElements.define("my-counter", MyCounter);

```


Crearlo Vanilla es muy buena opción, pero cuando son componentes mas complejos  vanilla no es tan agil, pero siempre hay que conocerla, por esto de que es importante siempre conocer las bases. 

Existen varias librerías, la mas importante y conocida es Polymer, pero la que me sorprendió últimamente por lo fácil y porque utilizan las buenas practicas de los frameworks, es Stencil JS. 

### IONIC y Stencil JS
Hace unos años cuando en ionic tomaron la decisión de que se pueda usar otros freameworks, para programar en ionic, no solamente en Angular, entonces ahí tomaron al decisión de usar webcomponents para todos sus componentes y no tener que crear componentes para cada librería. 

Todo esto llevo a que crearan su propia Librería llamada Stencil.js

Creemos el mismo componente que hicimos con Vanilla ahora con Stencil. 
```
$npm init stencil
```
Seleccionamos la opción de Component

Nos genera una estructura base con con un componente de ejemplo

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zwnpp2g0y3gvdy2ewdzn.png)

Pasamos a la carpeta y corremos `npm install`

Algo muy bueno, es que podemos correr un server local para probar nuestros components, lo probamos de la siguiente manera.
```
$npm run start
```

El server esta apuntando al index.html que tenemos en en el proyecto
```html
<!DOCTYPE html>
<html dir="ltr" lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
    <title>Stencil Component Starter</title>

    <script type="module" src="/build/designsystem.esm.js"></script>
    <script nomodule src="/build/designsystem.js"></script>
  </head>
  <body>
    <my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>
  </body>
</html>
```

Creamos el componente MyCounter

```
$npm run generate my-counter
```

```typescript
/* @jsx h */
import { h, Component, State, Host } from "@stencil/core";

@Component({
  tag: "my-counter",
  styleUrl: "my-counter.css",
  shadow: true,
})
export class MyCounter {
  @State() count: number = 0;

  inc() {
    this.count++;
  }

  dec() {
    this.count--;
  }

  render() {
    return (
      <Host>
        <button onClick={this.dec.bind(this)}>-</button>
        <span>{this.count}</span>
        <button onClick={this.inc.bind(this)}>+</button>
      </Host>
    );
  }
}
```
Y el my-counter.css
```css
* {
  font-size: 200%;
}

span {
  width: 4rem;
  display: inline-block;
  text-align: center;
}

button {
  width: 4rem;
  height: 4rem;
  border: none;
  border-radius: 10px;
  background-color: seagreen;
  color: white;
}
```

Y en el index.html lo agregamos

```html
<my-counter></my-counter>
```

Un caso de uso muy común para usar Webcomponents es para crear Sistemas de Diseño, como comentaba anteriormente las empresas que ya se conforman de equipos muy grandes, hay equipos que desarrollan con React, Angular, Vanilla etc, y ellos deben mantener una misma linea en sus componentes.


En un próximo Post crearemos un Mini Design System y ejemplos para usarlo con React o Angular.