Blog Arolla

[Devoxx France 2014] mon retour sur “Les Web Components”

Web components avec Google Polymer

Fin de première journée de Devoxx 2014, je vois une petite présentation sur Polymer, une biblothèque JS fournie par Google qui permet d'utiliser les Web Components dans ses applications Web. Vu que je suis en plein dans une mission de développement d'appli web bourrée de widgets qu'on voudrait réutilisables, je saute sur l'occasion.

J'ai donc cette question en tête : est-ce que je vais enfin pouvoir m'affranchir de "composants" dont les éléments sont répartis dans 2 à 5-6 fichiers différents ?

A Julian Jakubowski (Octo) et Romain Linsolas (Société Générale) d'apporter la réponse.

Une histoire de super-héros réutilisables...

Nos deux speakers nous vendent de la création de "super héros" avec l'API Marvel : le but est d'avoir un composant qui affiche un super-héros issu de l'API Marvel, correctement packagé et réutilisable. Si vous voulez revoir le code qu’ils ont utilisé, il est disponible sur Github.

Ils commencent avec une approche volontairement insatisfaisante de code copié/collé, puis commencent à définir un Web Component qui va factoriser le code existant.

Un Web Component se compose de deux parties :

  • Un template qui va définir le DOM du composant.
  • Du code JS qui fournit son comportement.

Où on apprend que Polymer n’a rien à voir avec le cumul des mandats

Ce Web Component est écrit avec la syntaxe Polymer : un tag <polymer-element> qui contient un tag <template> pour le html et un tag <script> pour la logique.

<polymer-element name="sample-component">
    <template>
        <!-- Code HTML -->
    </template>

    <script>
        // Code JS
    </script>
</polymer-element>

Polymer est une implémentation polyfill (via platform.js) de l'API Web Components HTML qui permet de compléter les lacunes des navigateurs dans le support de cette techno récente.

Nos deux speakers font évoluer peu à peu leur composant pour en faire un widget qui affiche une image du super-héros, son nom et sa description.

Ils nous montrent ensuite qu'en plus du DOM et du comportement écrit en Javascript, on peut également intégrer au composant une feuille de style, via une balise <style> qu'on insérera dans le template.

En utilisant le sélecteur :host, on désigne le composant, tout en ayant par ailleurs accès à tous les sélecteurs et toutes les règles de style habituelles. On peut également styler explicitement un composant web dans la feuille de style de la page en utilisant un sélecteur qui porte sur le composant lui-même.

Des arbres cachés dans l’ombre ?

Et là si vous avez bien tout suivi, vous devez vous dire qu'il y a une arnaque ou un truc. En effet, qu'est-ce qui m'empêche de faire un composant avec une feuille de style qui a des sélecteurs trop peu sélectifs et qui affectent des éléments en dehors du composant ?

Et dans l'autre sens, est-ce que des sélecteurs de notre application web ne risquent pas de dénaturer un composant inclus dans une de ses pages à cause d'une malheureuse coïncidence de nom de classe ou d'id ?

En somme, un Web Component ne semble pouvoir fonctionner que s'il est soigneusement isolé du reste de la page pour éviter des effets de bord.


Crédit Photo : Atilla Kefeli (CC BY-ND 2.0)

Les navigateurs ont une élégante solution à ce problème : le Shadow DOM. Il s'agit d'éléments qui sont rattachés au DOM principal, mais qui en sont isolés : ils seront rendus par le navigateur mais un parcours du DOM ne les traversera pas. Par ailleurs, les règles CSS sont cloisonnées entre le DOM principal et le Shadow DOM (en pratique, ce cloisonnement existe aussi entre toutes les arborescences qui existent dans le Shadow DOM pour éviter des interactions non désirées entre Web Components).

En plus d'être masqués, les éléments du Shadow DOM sont cloisonnés au niveau CSS : les styles déclarés dans un Web Component ne déteignent pas sur le reste du document et inversement.

Un template dans un verre d’eau

(Ce jeu de mots était complètement gratuit)

Les templates Polymer sont peuplés via un objet de modèle qui permet de remplacer des variables, indiquées entre doubles accolades. Cet objet est celui qui est renvoyé à la fin du script de composant.

Notez qu'il contient un attribut ready qui contient le callback utilisé par Polymer pour initialiser le composant quand son DOM sera chargé dans la page.

Notez également que l'on ne peut pas appeler une méthode du modèle directement dans le template, on doit utiliser une property avec le mot-clé get.

Voici à quoi ressemble le squelette complet d’un composant :

<polymer-element name="sample-component" attributes="sampleAttribute">
    <template>
        <h1>{{info}}</h1>
    </template>

    <script src="/scripts/script.js"></script>

    <script>
        var module = (function() {
            /* Méthodes privées */

            return {
                ready: function () {
                    /* Callback Polymer */
                },

                get info() {
                    /* Attribut */
                },

                /* Méthodes publiques */
            }
        })();

        Polymer('sample-component', module);
    </script>
</polymer-element>

Julian et Romain concluent sur la possibilité d'externaliser un ou plusieurs Web Components dans un fichier externe via  <link rel="import" ... />, ce qui soulèvera des questions sur les risques potentiels de XSS restées en suspens.

Voyons plus loin

Cette présentation m’a définitivement donné envie de creuser la question, mais il y a quelques points importants qui restent plutôt limitants pour une utilisation en production dans de nombreux projets :

  • Dans certaines circonstances, l’utilisation d’imports HTML peut bloquer le rendu. On veillera à suivre les recommandations du site HTML5 Rocks pour éviter les principaux écueils.
  • Le support d’Internet Explorer est condamné à ne pas être performant : IE n’implémente ni le Shadow DOM, ni les templates HTML. Si Polymer fournit un polyfill pour IE10+ (fonctionne également avec IE9 même si le support de ce navigateur n’était pas prévu), les performances vont forcément s’en ressentir. Les données fournies par Can I Use ? n'inspirent pas l'optimisme :

Si toutefois ça ne vous décourage pas de tenter l’expérience, je termine avec quelques infos pour la route.

Romain Linsolas vient de publier sur son propre blog une introduction avec Web Components avec un exemple différent et des explications plus détaillées. C’est un bon point de départ pour utiliser Polymer :

Polymer est distribuée comme package Bower, vous aurez donc besoin de Node.js et Bower. Comme le dit Romain dans son article, Yeoman et Grunt vous faciliteront la vie si vous travaillez en local (les imports HTML ont des restrictions de sécurité assez sévères en local, il est donc peu pratique de travailler avec eux sans que le site web soit servi par un serveur Web).

Et si vous êtes du genre velu, vous pouvez également vous plonger dans les spécifications W3C du Shadow DOM et des HTML Templates. N'hésitez pas à me faire part de vos retours sur cette techno, tout particulièrement si vous faites partie des téméraires à l'avoir utilisée en prod.

Les présentations comme celles-ci sont celles que je préfère à Devoxx : elles donnent envie d'en savoir plus tout en proposant suffisamment de contenu concret, même après avoir fait quelques expériences moi-même j'ai abandonné l'idée d'utiliser Polymer pour des Web Components custom chez mon client actuel. Mais ce n'est que partie remise...

Plus de publications

Développeur JEE et passionné d'informatique

1 comment for “[Devoxx France 2014] mon retour sur “Les Web Components”

  1. Jérôme
    12 mai 2014 at 12 h 56 min

    Salut,

    Pour ton problème de composant, tu peux regarder du côté de react qui a une approche similaire
    – code + template dans le même fichier
    – fonction cycle de vie (ready, render, …)

    Par contre il faut une chaine de build pour construire les composants (JSX), et il n’y a pas d’isolation des CSS.