“Two people with a laptop and a tablet shopping online on a table with gift wrapping paper” by rawpixel on Unsplash

WebComponent : Custom element V1

La spec des WebComponents mettant du temps a être finalisée, on a eu droit à l’implémentation par les browsers de la v0 de l’api Custom Elements et de Shadow Dom. Sauf que voilà, le temps à passé, la spec finale n’est toujours pas dehors et des choses ont déjà changé. On a maintenant la v1 et des changements notables. Voilà donc ce qu’il faut savoir pour mettre à jour vos composants devenus legacy.

L’objet customElements

Une des nouveautés c’est l’objet customElements. Là ou avant on passait par des méthodes de document comme document.registerElement, aujourd’hui on passe par l’objetwindow.customElements. Celui-ci contient 4 méthodes principales qui nous permettront d’interagir avec la spec customElements :

  1. define(name, Class [,options]) : qui nous permet de définir notre composant. C’est ce que vous allez appeler pour dire que votre class JS correspond à l’élément html nommé my-element. La partie option est utile pour spécifier des options comme le extend.
    ex: customElements.define('my-comp', MyCompClass);
  2. get(name) : qui nous permet de récupérer la class du constructeur de l’élément passé en paramètre (nom).
  3. upgrade() : Cette fonction met à jour explicitement un custom element indéfini. Par exemple, si un custom élément est créé via le setterinnerHTML dans un noeud parent qui n’est lui non plus pas encore attaché au document, le custom element ne sera pas activé tant qu’il n’est pas connecté. Dans ce cas, il faut que le développeur soit capable de faire l’activation manuellement, et ce sera faisable grâce à cette méthode.
  4. whenDefined(name) : très pratique, cette fonction nous retournera une promesse qui sera invoqué dès que le custom élément (passé en paramètre) sera définit. Ceci nous permettra de faire des actions de manière asynchrone sur les objets.

Les life-cycles methods

Dans la spec v0, nous avions 4 méthodes qui composaient le cycle de vie de nos composants. A présent, nous en avons plus que 3 et les comportements autorisés ont changés.

  1. createdCallback() devient constructor`. Les WebComponents pouvant être facilement déclaré en ES6, c’est le constructeur de class qui a été choisi pour prendre place à la création. La limitation est que la manipulation du DOM du composant ne pourra plus se faire dans ce constructeur sous peine de se prendre une DOMException: Failed to execute ‘createElement' on ‘document': The result must not have children.
  2. attachedCallback devient connectedCallback. Comme auparavant cette méthode est déclanchée lorsque le composant est attaché au DOM. C’est donc l’endroit idéal pour mettre en place vos EventListener` et initialiser le DOM du composant.
  3. detachedCallback devient disconnectedCallback. A nouveau pas de changement autre que le nom pour cette méthode. A l’inverse de attachedCallback c’est ici qu’il faut supprimer les EventListener mis en place et effectuer les teardown.
  4. attributeChangedCallback lui garde le même nom, mais son déclenchement a subit quelques modifications (voir chapitre dédié ci-dessous).
  5. adoptedCallback est appelé lorsque le CustomElement a été déplacé dans un nouveau document. Typiquement via un document.adoptNode(el). Mais cette fonctionnalité est moins fréquemment utilisée.

AttributeChangedCallback

Dans la v0, toutes modifications d’attribut déclenchaient ce callback. Dorénavant, et pour éviter de consommer trop de ressource, il sera nécessaire de lister explicitement quels attributs nous voulons observer. Pour cela, la class du composant devra déclarer un tableau static comme celui-ci :

static get observedAttributes() { return ['attr1', 'attr2']; }

Nouveau polyfill

Comme la spec a changé, le polyfill webcomponentjs devrait aussi être mis à jour. Actuellement, c’est le polyfill document-register-element qui est le plus performant pour remplacer la spec pour les vieux navigateurs.

Creation d’éléments

Cette partie là n’a pas changé. Comme dans la v0, la création peut passer soit par l’instantiation de la class var el = new MyCustomElement(), soit via la méthode du DOM document.createElement('my-customelement').

Finalement…

et après avoir utilisé cette nouvelle version, je la trouve beaucoup plus aboutie. Nous avons à présent le contrôle sur les attributs à observer, et l’extension d’éléments existants fonctionne maintenant parfaitement, même en ES6. Que vouloir de mieux ? Une spec définitive peut-être, oui…