Les composants sont un vieux rêve de développeur. Un truc que tu prendrais sur étagère et lâcherais dans ton application, et qui marcherait directement et apporterait la fonctionnalité à tes utilisateurs sans rien faire. Mes amis, cette heure est venue. Oui, bon, peut-être. En tout cas, on a le début d’un truc. Ce n’est pas complètement neuf. On avait déjà la notion de composants dans le développement web depuis quelque temps, mais ils demandaient en général de lourdes dépendances comme jQuery, Dojo, Prototype, AngularJS, etc. Pas vraiment le genre de bibliothèques que tu veux absolument ajouter à ton application. Les Web Components essaient de résoudre ce problème : avoir des composants réutilisables et encapsulés.

Ils reposent sur un ensemble de standards émergents, que les navigateurs ne supportent pas encore parfaitement. Mais quand même, c’est un sujet intéressant, même si on ne pourra pas en bénéficier pleinement avant quelques années, ou même jamais si le concept ne décolle pas.

Ce standard émergent est défini dans trois spécifications : • Custom elements ("éléments personnalisés") • Shadow DOM ("DOM de l’ombre") • Template

Custom elements Les éléments customs sont un nouveau standard qui permet au développeur de créer ses propres éléments du DOM, faisant de <ns-pony></ns-pony> un élément HTML parfaitement valide. La spécification définit comment déclarer de tels éléments, comment tu peux les faire étendre des éléments existants, comment tu peux définir ton API, etc. Déclarer un élément custom se fait avec un simple customElements.define :

class PonyComponent extends HTMLElement {
  constructor() {
  super();
  console.log("I'm a pony!");
  }
}
customElements.define('ns-pony', PonyComponent)

Et ensuite l’utiliser avec : <ns-pony></ns-pony> Note que le nom doit contenir un tiret, pour indiquer au navigateur que c’est un élément custom. Évidemment ton élément custom peut avoir des propriétés et des méthodes, et il aura aussi des callbacks liés au cycle de vie, pour exécuter du code quand le composant est inséré ou supprimé, ou quand l’un de ses attributs est modifié. Il peut aussi avoir son propre template. Par exemple, peut être que ce ns-pony affiche une image du poney, ou seulement son nom :

class PonyComponent extends HTMLElement {
  constructor() {
  super();
  console.log("I'm a pony!");
  }
  /**
  * This is called when the component is inserted
  */
  connectedCallback() {
  this.innerHTML = '<h1>General Soda</h1>';
  }
}

Si tu jettes un coup d’œil au DOM, tu verras

“General Soda”

Mais cela veut dire que le CSS ou la logique JavaScript de ton application peut avoir des effets indésirables sur ton composant. Donc, en général, le template est caché et encaspulé dans un truc appelé le Shadow DOM ("DOM de l’ombre"), et tu ne verras dans le DOM que , bien que le navigateur affiche le nom du poney.

Shadow DOM Avec un nom qui claque comme celui-là, on s’attend à un truc très puissant. Et il l’est. Le Shadow DOM est une façon d’encapsuler le DOM de ton composant. Cette encapsulation signifie que la feuille de style et la logique JavaScript de ton application ne vont pas s’appliquer sur le composant et le ruiner accidentellement. Cela en fait l’outil idéal pour dissimuler le fonctionnement interne de ton composant, et s’assurer que rien n’en fuit à l’extérieur. Si on retourne à notre exemple précédent

class PonyComponent extends HTMLElement {
  constructor() {
  super();
  const shadow = this.attachShadow({ mode: 'open' });
  const title = document.createElement('h1');
  title.textContent = 'General Soda';
  shadow.appendChild(title);
  }
}
<ns-pony>
  #shadow-root (open)
  <h1>General Soda</h1>
</ns-pony>

Désormais, même si tu ajoutes du style aux éléments h1, rien ne changera : le Shadow DOM agit comme une barrière. Jusqu’à présent, nous avions utilisé une chaîne de caractères pour notre template. Mais ce n’est habituellement pas la façon de procéder. La bonne pratique est de plutôt utiliser l’élément <template>

Template Un template spécifié dans un élément <template> n’est pas affiché par le navigateur. Son but est d’être à terme cloné dans un autre élément. Ce que tu déclareras à l’intérieur sera inerte : les scripts ne s’exécuteront pas, les images ne se chargeront pas, etc. Son contenu peut être requêté par le reste de la page avec la méthode classique getElementById(), et il peut être placé sans risque n’importe où dans la page. Pour utiliser un template, il doit être cloné :

<template id="pony-template">
  <style>
  h1 {
  color: orange;
  }
  </style>
  <h1>General Soda</h1>
</template>