IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Débat: Les Web Components, pour le meilleur et pour le pire ?

Les Web Components ont fait beaucoup parler d'eux depuis l'avancée des dernières spécifications et le développement de polyfills permettant de les utiliser dès maintenant. Ils ont même été décrits par plusieurs articles de presse comme la prochaine révolution du développement web. Mais cet engouement est-il justifié ? Pour aller à contre-courant de la multitude d'articles en vantant les mérites, nous allons détailler dans cet article l'intérêt discutable, les limitations, les inconvénients et les mauvais cas d'utilisation des Web Components.

24 commentaires Donner une note à l´article (5) 

Article lu   fois.

L'auteur

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Les promesses des Web Components

I-A. Un standard pour les composants d'interface en JavaScript

La particularité de cette spécification est qu'elle vient influencer la manière dont nous codons nos pages HTML en y ajoutant une approche résolument modulaire. Les composants viennent se situer hiérarchiquement entre le document et les éléments ; on peut les concevoir comme des groupes autonomes d'éléments formant un bloc identifiable visuellement et fonctionnellement.

Ainsi, ils se substituent assez bien au concept de widgets, ces composants d'interfaces déjà popularisés depuis de nombreuses années par des bibliothèques comme jQueryUI, YUI (abandonné il y a peu par Yahoo) ou encore les widgets Dojo. Le net avantage des Web Components par rapport à ces bibliothèques est la simplicité d'intégration, puisqu'il suffit d'utiliser la balise personnalisée dans votre HTML pour charger le composant. Les développeurs de composants sont encouragés à permettre le paramétrage de ces composants directement via des attributs HTML, afin que le composant puisse être utilisé sans écrire une ligne de JavaScript. Toutefois, une simple déclaration HTML ne peut égaler la flexibilité du paramétrage et de l'initialisation JavaScript, c'est pourquoi certains Web Components complexes s'utilisent encore par le biais d'une API JavaScript.

Ce nouveau standard devrait donc en théorie sonner le glas de ces différentes bibliothèques UI, ce qui fait que nous n'aurions plus à nous préoccuper des dépendances propres à chaque widget trouvé sur le Net. En théorie seulement, car on trouve déjà de nouvelles bibliothèques regroupant des Web Components avec un format, un style et des spécificités qui leur sont propres :  Polymer de Google et Brick de Mozilla par exemple. Pour l'instant, ils font des efforts en matière d'interopérabilité, mais nous n'avons aucune garantie que cela restera le cas avec l'apparition d'autres bibliothèques de ce genre. Malheureusement, les bibliothèques de Web Components semblent tomber dans les mêmes travers que les bibliothèques de widgets en leur temps.

I-B. Simplifier et étendre la syntaxe HTML

Une critique récurrente du HTML par les développeurs d'applications web riches est le nombre restreint d'éléments à disposition : des grands absents comme les barres d'onglets, les tooltips (infobulles) ou les overlays (masques d'arrière-plan) se font toujours désirer. Tout le problème du point de vue des organismes de standardisation est de définir la nature de ces éléments, et de s'assurer qu'ils présentent un sens pour tous les usages et contextes qu'offre le Web. Par exemple, quelle différence y a-t-il entre une barre d'onglets, un menu accordéon, et une barre de navigation classique chargeant du contenu via AJAX ? Certes, chacun dispose de caractéristiques visuelles particulières qui nous permettent de les différencier. Mais sur le plan sémantique et fonctionnel, c'est une autre affaire. C'est pourquoi les descriptions des éléments standards sont volontairement abstraites : <article> ne contient pas forcément un article au sens publication, tandis que <figure> peut convenir à la fois pour des images, des schémas ou des bouts de code.

Puisqu'avec les Web Components, chacun est libre de créer les balises de son choix, le futur HTML sera sans doute beaucoup plus diversifié et concret. Bonne ou mauvaise nouvelle ? Les développeurs s'en réjouissent au premier abord, mais un HTML trop spécifique et disparate pourrait nuire à l'ubiquité du Web : si les experts du W3C et du WHATWG prennent bien le temps de peser le pour et le contre à l'introduction d'un nouvel élément, il y a peu de chances que nous fassions preuve d'autant de réflexion (surtout un vendredi soir sur un projet en retard Image non disponible). Un élément barre d'onglets <tabs-bar> peut être une fausse bonne idée s'il doit être remanié en menu déroulant sur les petits écrans.

Le Web se transforme sans cesse et ses usages s'étendent à de nouvelles classes d'appareils. Ce phénomène semble s'accentuer avec le temps, ce qui me laisse à croire que la vision que nous avons du Web est encore très limitée : le Web n'a que 25 ans, et il a déjà changé de visage plus d'une fois (Web 2.0, révolution mobile…). Aujourd'hui plus que jamais, nous avons besoin de prendre du recul sur la conception de nos pages Web et de nous concentrer sur le contenu, à travers un HTML générique et sémantique. Un HTML à l'abstraction et aux limites nécessaires, qui ne parte pas dans toutes les directions et qui ne se banalise pas, car son rôle est bien plus important qu'on ne le croit.

C:\Article_Dvp\documents\web-components-debat\images\overenthusiastic.png
Certains font preuve d'un enthousiasme exagéré vis-à-vis des Web Components… Source : http://addyosmani.github.io/fitc-wccdt/

I-C. Standardiser le templating côté client

L'introduction des Web Components amène également la balise <template>, dont la fonction est très particulière : elle contient un fragment de HTML qui sera chargé sans être activé : c'est-à-dire que tous les éléments à l'intérieur sont inertes avant d'être utilisés : les images ne sont pas chargées, les <script> ne sont pas exécutés, les <video> et <audio> ne sont ni chargés ni joués… Ce HTML inerte peut par la suite être « activé » en copiant son contenu et en l'insérant en JavaScript à l'endroit désiré dans le document.

Cette nouvelle balise est pressentie pour standardiser le templating côté client, comme le souligne cet article sur HTML5Rocks.com . Or, il n'en est rien. Comme nous le verrons en section IV de cet article, cet objectif est bien trop large et abstrait pour être atteignable. Les auteurs de la spécification en ont bien conscience et n'ont pas même pas essayé d'aller dans cette voie. En réalité, la spécification est très limitée dans son champ d'application. Il s'agit simplement d'un conteneur de HTML à réserver pour plus tard, ce que beaucoup de bibliothèques de templating client avaient déjà réussi à faire par le biais de balises <script> avec un attribut type spécial.

Tous les autres usages envisagés, et en particulier son rôle de pierre angulaire dans les solutions de templating côté client, ne sont que pure extrapolation de la part des développeurs. Actuellement, la spécification présente plus de contraintes que d'avantages comparée aux solutions existantes à base de <script>. Elle a le mérite d'enfin apporter un standard pour un mécanisme utilisé et éprouvé depuis des années. Mais tout comme les imports HTML, elle semble arriver trop tard et les éléments <template>seuls ne servent à rien sans JavaScript pour les activer.

II. Custom Elements : <mon-element-a-moi>

II-A. Adieu les définitions de type de document (DTD)

HTML, un descendant de SGML (Standard Generalized Markup Language), a pu jusqu'à sa version 4 être décrit par des DTDDéfinition de type de document, c'est-à-dire des descriptions techniques formelles du langage qui faisaient notamment la liste des balises admises dans le langage.

Extrait de la DTD HTML4 disponible ici : Languehttp://www.w3.org/TR/html4/sgml/dtd.html
Sélectionnez
<!ELEMENT IMG - O EMPTY                -- Embedded image -->
<!ATTLIST IMG
  %attrs;                              -- %coreattrs, %i18n, %events --
  src         %URI;          #REQUIRED -- URI of image to embed --
  alt         %Text;         #REQUIRED -- short description --
  longdesc    %URI;          #IMPLIED  -- link to long description
                                          (complements alt) --
  name        CDATA          #IMPLIED  -- name of image for scripting --
  height      %Length;       #IMPLIED  -- override height --
  width       %Length;       #IMPLIED  -- override width --
  usemap      %URI;          #IMPLIED  -- use client-side image map --
  ismap       (ismap)        #IMPLIED  -- use server-side image map --
  >

Grâce aux DTDDéfinition de type de document, les éléments de la page sont systématiquement décrits et normalisés. Ces éléments connus, les navigateurs disposent d'informations pour déduire la hiérarchie du document et le représenter plus efficacement.

Parmi les cousins les plus connus du HTML, XML offre bien plus naturellement aux développeurs la possibilité d'utiliser leurs propres balises pour décrire les données ; les DTD qui les accompagnent font office de contrat d'interface très fiable, faisant du XML un bon choix pour la communication entre serveurs et web services.

HTML a pris un autre chemin. Les interpréteurs dans les navigateurs sont conçus pour être très tolérants, en acceptant les erreurs de syntaxe et en tentant de les corriger : c'est pourquoi la plupart des navigateurs web parviennent à fermer automatiquement certaines balises, à afficher des balises inconnues ou à ignorer les attributs et valeurs non standardisées. De ce fait, les développeurs Web ont toujours fait preuve de beaucoup de négligence sur la qualité et la validité stricte du HTML qu'ils produisaient. Si vous avez déjà utilisé un validateur HTML (on en trouve des dizaines gratuits en ligne, dont celui du W3C : http://validator.w3.org/), vous avez sans doute déjà essayé de faire valider certains sites grand public et le nombre d'erreurs relevées a dû vous surprendre.

C:\Article_Dvp\documents\web-components-ne-vont-pas-revolutionner\images\validator.png

Ainsi, les développeurs HTML n'ont jamais vraiment porté grande importance aux DTD. Depuis HTML5, les éléments n'ont d'ailleurs plus à respecter les contraintes d'une DTD ; ce que les développeurs ont très bien accueilli par le simple fait que cela leur simplifiait la déclaration du DOCTYPE :

Déclaration DTD HTML4.01 transitional
Sélectionnez
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
Déclaration DTD HTML5
Sélectionnez
<!DOCTYPE html>

Avec les Custom Elements (éléments personnalisés), cette flexibilité va encore plus loin puisque de nouveaux types d'éléments peuvent être définis côté client a posteriori de la création du document ; ce que n'a jamais permis une DTDDéfinition de type de document. La majorité des articles autour des Custom Elements ne font d'ailleurs aucune mention des DTDDéfinition de type de document, ce que je trouve très étonnant. Du temps du HTML4, si on avait demandé à un développeur de déclarer des balises personnalisées, il aurait tout de suite pensé à une DTD personnalisée.

Malgré le fait que le HTML5 se soit émancipé des DTDDéfinition de type de document, on pourrait tout de même en parler ne serait-ce qu'à titre de comparaison.

II-B. Shadow DOM : le cache-misère officiel

Les Custom Elements sont composés d'éléments HTML standards. Ce ne sont pas des nouvelles briques mais un assemblage de briques existantes agrémentées de JavaScript et de déclarations CSS isolées. Il est important de comprendre que tout ce que l'on peut faire avec les Custom Elements peut déjà être fait aujourd'hui : il s'agit simplement d'un emballage, d'un paquet cadeau à destination des développeurs, destiné à normaliser la définition et l'intégration d'éléments d'interface aussi appelés widgets, bien que le terme semble être passé de mode.

Puisque tout l'intérêt des Custom Elements est d'avoir un bel emballage, il faut veiller à ce que le contenu de ces éléments soit bien emballé et caché d'un regard extérieur tant que l'on n'a pas ouvert la boîte: c'est de là que vient l'idée du Shadow DOM.

Mais que cherche-t-on à cacher exactement ? Qu'y a-t-il de si affreux et verbeux dans notre HTML pour que l'on souhaite le faire disparaître ? Tous les exemples donnés dans les articles sur ce sujet sont criants de vérité : c'est l'utilisation abusive de markup à des fins de mise en forme.

En effet, il semble tout à fait normal pour certains auteurs d'articles sur le sujet que l'on distingue en HTML un markup de présentation d'un markup de contenu. Le markup pour le style, ce n'est pas sans rappeler la mise en page par tableaux qui avait ses émules entre 1995 et 2005 : utiliser des éléments <table>, <tr> et <td> pour aligner et dimensionner les éléments au mépris de la sémantique du document. Si la mise en page par tableaux est aujourd'hui considérée comme une mauvaise pratique (et même source de moqueries pour certains web designer seniors), force est de constater que l'utilisation abusive de <div> et de <span>, aussi appelée « soupe de div », ne fait guère mieux. On comprend mieux pourquoi on souhaite la cacher.

Image non disponible
Le Shadow DOM, ou la politique de l'autruche

Voici un extrait des Web Components Best Practices issu du site communautaire webcomponents.org:

Don't put too much in Shadow DOM : Shadow DOM allows you to stuff a bunch of complex junk out of sight. However, that's not an excuse to have as many DOM elements as you want in your shadow, as more elements will still lead to worse performance. In addition, try to keep your configuration and state visible by keeping anything semantic exposed in the logical DOM. Cruft goes in the Shadow; semantic stuff doesn't.

Traduction: Ne chargez pas trop votre Shadow DOM : Le Shadow DOM vous autorise à fourrer votre camelote à l'abri des regards indiscrets. Cependant, ce n'est pas une excuse pour avoir autant d'éléments DOM que vous avez envie dans votre Shadow DOM, car un nombre croissant d'éléments conduira immanquablement à empirer les performances. De plus, essayez de garder votre configuration et vos états applicatifs visibles en maintenant tout ce qui relève de la sémantique dans le DOM logique. Vos cochonneries vont dans le Shadow DOM, les éléments sémantiques non.

S'agit-il là de l'aveu qu'un HTML purement sémantique est impossible ? Ou juste trop difficile à atteindre ? Notez les mots employés : junk (camelote) et Cruft (cochonneries). Doit-on vraiment accepter cela et normaliser un HTML camelote ?

Mon opinion est qu'il ne devrait pas y avoir du tout de markup de présentation. D'ailleurs, toutes les balises dites de présentation telles que <center>, <font> ou <b> ont été dépréciées ou adaptées en HTML5. S'il reste certains cas nécessitant de modifier le markup uniquement à des fins de style, alors les standards doivent évoluer pour régler ces cas au lieu de les tolérer et de chercher à les dissimuler.

Le Shadow DOM est un cache-misère. Certains diront qu'il s'agit d'une solution pragmatique et court-termiste à ce problème. Je pense personnellement que c'est tout sauf une solution : il ne résout pas le problème du HTML trop verbeux, mais se contente de cacher la poussière sous le tapis. Au contraire, en masquant le problème, cela pourrait encourager les développeurs à persister dans cette mauvaise pratique et ne faire qu'empirer les choses. D'autres diront qu'il présente un intérêt pour l'isolation des règles CSS. Je leur répondrai qu'il existe d'autres moyens pour y parvenir sans avoir à fragmenter le document: <style scoped> @import "composant.css"; </style>

HTML5 a amené une vingtaine de nouvelles balises liées à la structure et à la sémantique du document, tandis que les évolutions de CSS réduisent peu à peu la nécessité de recourir à de multiples éléments à des fins de mise en forme. Il s'agit clairement de la direction à suivre, en s'attaquant au problème de front. C'est pourquoi le Shadow DOM doit rester à sa place: à l'ombre !

II-C. Pas si custom que ça

Avec les Custom Elements, on s'autorise à ce que le HTML parte dans toutes les directions à partir du moment où les propriétés de ces nouveaux éléments accompagnent le document : est-ce réellement une bonne idée ? Outre le fait de charger un peu plus encore les requêtes, on vient surcharger les propriétés établies par défaut par le navigateur pour chaque élément.

En effet, chaque navigateur implémente sa propre feuille de style, appelée User Agent Stylesheet, qui définit les propriétés CSS de base des éléments des pages que vous consultez. Ce sont ces règles que vous surchargez en définissant vos propres feuilles de style pour vos sites. Or, les User Agent Stylesheets varient selon le navigateur ; c'est ce qui explique que vous n'ayez pas tout à fait le même rendu d'un navigateur à un autre (ça et quelques détails d'implémentation des moteurs de rendu).

Sur un même navigateur, elles peuvent varier également ; par l'ajout d'extensions, de feuilles de styles propres à l'utilisateur (userstylesheets), de détails spécifiques au terminal (par exemple un navigateur Android selon s'il est installé sur un smartphone ou une tablette), ou encore d'outils dédiés à certains handicaps : ces outils peuvent agrandir les textes, augmenter le contraste, fournir des moyens de saisie et de navigation assistés, simplifier la mise en page, etc.

Ces variations sont utiles et nécessaires : le développeur ne devrait en aucune façon chercher à les annihiler pour que son site s'affiche de la même manière sur tous les navigateurs. Or, plus on définit les propriétés d'éléments, moins les règles par défaut s'appliquent. Ce contrôle absolu de l'apparence et du comportement du composant peut également poser des problèmes d'accessibilité. Heureusement, l'accessibilité n'a pas été oubliée par tous les développeurs de Web Components et fait déjà partie des préoccupations des auteurs de Polymer; il faudrait idéalement qu'elle ne soit oubliée par personne.

Pour mieux comprendre quel est le problème exactement, prenons un exemple parlant et intéressons-nous un moment au cas du sélecteur de dates (datepicker). C'est un cas que j'ai rencontré plusieurs fois et qui m'a vraiment aidé à comprendre les enjeux de la standardisation d'éléments.

En HTML4, les boîtes de saisie sont très limitées dans les formulaires et le seul moyen de sélectionner une date est de la saisir dans un certain format : DD/MM/YYYY par exemple. Une validation de format est ensuite effectuée côté serveur, et parfois côté client également. Tout cela est assez fastidieux à la fois pour l'utilisateur comme pour le développeur. Ainsi, le widget DatePicker est rapidement devenu un classique des bibliothèques de widget. Voilà à quoi ressemble celui de jQueryUI :

Image non disponible

Ensuite, avec HTML5 est apparu <input type="date">. Maintenant que le type de donnée attendu est connu des navigateurs, ceux-ci peuvent proposer leurs propres datepicker conçus spécifiquement pour chaque terminal et navigateur ; ce qui se traduit par un moyen de saisie plus adapté et ergonomique. Opera a été parmi les premiers à implémenter un datepicker ; ils sont ensuite apparus sur divers navigateurs mobiles. Voilà un aperçu de certains datepicker « natifs » existants :

Image non disponible
Datepickers natifs sur Chrome, iOS, BlackBerry et Android

Notez la différence d'ergonomie entre un datepicker pour souris comme celui de Chrome et un datepicker pour écran tactile comme sur iOS ; ou la différence entre les datepicker Android selon la taille d'écran. Les datepicker JavaScript ne pourront jamais s'adapter aussi bien selon le contexte ; de plus, les utilisateurs sont accoutumés à utiliser les composants natifs fournis par leur navigateur et leur système : ils sauront l'utiliser sans problème.

Certes, tous les navigateurs ne proposent pas encore de widgets : Firefox et Internet Explorer considèrent encore ces types de champ comme de simples champs texte. Mais il est possible de détecter le support de datepicker natif et de charger un datepicker JavaScript comme solution de secours (un tutoriel est disponible ici). Le widget pourrait faire lui-même ce test, ou au moins proposer un paramétrage à cet effet. Cependant, ce n'est généralement pas l'approche choisie par les développeurs de ces widgets : ils préfèrent choisir très précisément le style et le comportement de leur widget, quitte à négliger l'adaptation au terminal.

Et c'est le même topo pour les Web Components : alors que la spécification est toujours à l'étude, on voit déjà plusieurs composants sélecteurs de date faire leur apparition, dont la grande majorité ne se préoccupent pas de tester le support de <input type="date">. Il y a de rares exceptions comme celui-ci qui agit comme un polyfill. Mais pourquoi alors utiliser un Custom Element quand un polyfill sur l'élément input fonctionne tout aussi bien ?

En résumé, un des risques majeurs liés à l'usage excessif de Custom Elements est celui de surcharger excessivement les styles par défaut d'éléments standards ou de ne pas utiliser les éléments standards appropriés, ce qui nuit à l'ergonomie et l'accessibilité de vos composants.

III. HTML imports : arrivés après la bataille

III-A. Alors qu'on ne les attendait plus

Nous composons nos pages HTML de manière modulaire depuis de nombreuses années. L'inclusion de HTML est une des fonctionnalités les plus basiques de tout langage de vues côté serveur ; elle préfigure souvent dans les tutoriels. Ainsi, ces lignes de code ne devraient pas vous être inconnues :

Instructions d'inclusion de pages dans différents langages serveur
Sélectionnez
<?php include 'header.php'; ?>

<jsp:include page="header.jsp" />

<!-- #include file="header.asp" -->

Sans langage serveur, c'est-à-dire avec un serveur web statique, il existe également plusieurs moyens d'inclure une page dans une autre. Lorsque j'ai fait mes débuts en développement web il y a douze ans, les framesets étaient à la mode :

Exemple d'utilisation des framesets
Sélectionnez
<frameset rows="20%,80%">
   <frame name="header" src="header.html" />
   <frame name="main" src="main.html" />
   <noframes>Your browser does not support frames.</noframes>
</frameset>

Ensuite on a voulu apporter une solution moins intrusive et plus discrète : les iframes

Exemple d'utilisation d'un iframe
Sélectionnez
<iframe src="header.html"></iframe>

Puis on s'est aperçus qu'en bricolant un peu, on pouvait se débrouiller avec JavaScript pour composer nos vues tout en conservant un seul document :

page.html
Sélectionnez
<script src="header.html.js"></script>
header.html.js
Sélectionnez
document.write("<h1>contenu échappé de header.html ici</h1>");

Enfin, AJAX est arrivé et tout est devenu beaucoup plus facile :

Exemple d'utilisation d'AJAX pour inclure une page HTML
Sélectionnez
<script>
	function include(src){
		var scriptRef = document.scripts[document.scripts.length-1];
		var xhr = new XMLHttpRequest();
		xhr.onreadystatechange = function(){
			if (xhr.readyState==4 && xhr.status==200){
				scriptRef.outerHTML = xhr.responseText;
			}
		};
		xhr.open("GET", src, true);
		xhr.send();
	}
</script>
</head>
<body>
<script>include("header.html");</script>

Nous avons donc aujourd'hui tout un panel de solutions éprouvées à disposition. La dernière en date, AJAX, est utilisée couramment depuis 2006, soit depuis plus de huit ans. Et voilà qu'en 2014 arrive timidement une spécification pour les imports HTML. Encore au statut de Working Draft au W3C, on peut espérer dans le meilleur des cas l'utiliser à la mi-2015 avec un polyfill AJAX comme parachute. Mais qu'avons-nous à y gagner à utiliser cette nouvelle spécification par rapport à AJAX ou de la composition côté serveur ? Les solutions actuelles basées sur AJAX sont plus flexibles et leur large support jouera en leur faveur encore plusieurs années.

III-B. Un import seul ne sert à rien

Les imports HTML ne font pas vraiment ce qu'ils sont supposés faire au premier abord : ils n'ajoutent aucun HTML directement dans votre document. Ils se contentent de charger le document HTML afin que vous puissiez l'exploiter ensuite en JavaScript. Est-ce que vous vous attendiez à cela ? Alors que toutes les instructions d'import dans les langages serveur comme PHP, JSP ou ASP chargent le contenu et l'insère à l'endroit de l'instruction, un import HTML ne fait rien du tout avec le contenu. C'est totalement contre-intuitif et ne suit pas les autres comportements de la balise <link>. Imaginez que les feuilles de styles CSS importées ne s'appliquent pas par défaut sur le document, et qu'il faille les activer manuellement en JavaScript.

Par ailleurs, cela rend caduc l'avantage supposé de cette solution comparée à celles qu'on utilisait jusque-là : l'import de HTML par balises <script> ou par AJAX nécessite également un recours au JavaScript, avec un code de taille similaire :

Comparaison d'une méthode include via AJAX et via import link
Sélectionnez
function include_AJAX(src){
	var scriptRef = document.scripts[document.scripts.length-1];
	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange = function(){
		if (xhr.readyState==4 && xhr.status==200){
			scriptRef.outerHTML = xhr.responseText;
		}
	};
	xhr.open("GET", src, true);
	xhr.send();
}

function include_import(src){
	var scriptRef = document.scripts[document.scripts.length-1];
	var link = document.createElement('link');
	link.rel = 'import';
	link.onload = function(e) {
		var body = link.import.querySelector("body").cloneNode(true);
		scriptRef.outerHTML = body.innerHTML;
	};
	link.href = src;
	document.head.appendChild(link);
}

Ce qui amène des incohérences assez amusantes, par exemple dans l'article de HTML5Rocks:

AJAX - I love xhr.responseType="document", but you're saying I need JS to load HTML? That doesn't seem right.
J'adore xhr.responseType="document", mais vous dites que j'ai besoin de JavaScript pour charger du HTML ? Ça ne semble pas être l'idéal.

Et plus loin…

Including an import on a page doesn't mean "plop the content of that file here". It means "parser, go off an fetch this document so I can use it". To actually use the content, you have to take action and write script.
Inclure un import dans une page ne signifie pas « mets le contenu de ce fichier ici ». Cela signifie : « parseur, va charger ce document afin que je puisse l'utiliser ». Pour utiliser concrètement le contenu, vous devez agir dessus en JavaScript.

Il est évident que l'on importe du HTML pour se servir de ce contenu : alors, d'où vient cette drôle d'idée de ne pas pouvoir se servir du contenu sans recourir au JavaScript ? Justement du fait qu'ils arrivent trop tard : les solutions complexes mises en place dans les frameworks JavaScript pour gérer les vues et sous-vues proposent un panel de fonctionnalités que HTML seul ne pourra jamais rivaliser avec. L'utilisation de JavaScript est une trappe de sortie pour la spécification qui lui permet d'esquiver sa pauvreté apparente et ne pas devoir faire face à un constat amer : celui qu'elle arrive avec quinze ans de retard.

IV. La balise <template> : la coquille vide qui veut régner sur l'océan

 

IV-A. Mille solutions à un seul problème

Il y a un an, je publiais ici un article décrivant tout ce qu'il y a à savoir sur le templating côté client. J'ai écrit cet article en m'imposant une consigne : celle de ne pas privilégier une approche plutôt qu'une autre, mais au contraire de toutes les parcourir, les illustrer par l'exemple et les comparer.

En explorant les différentes approches, je me les suis représenté en les positionnant sur un axe simple : cet axe va de « Full Logic » à « Logic-less » selon la quantité de logique présente dans le template. Mais les différences vont bien au-delà de ça. Tout comme on ne peut pas réduire la politique à la gauche ou la droite, on ne peut pas résumer une solution de templating à la richesse syntaxique de ses templates. Le temps de rendu, la pré-compilation, le pre-processing, les méthodes de rendu partiel, l'asynchronicité du rendu ou encore l'empreinte sur le DOM sont autant de critères à prendre en compte.

La conclusion de cet article sur le templating côté client était sans appel : il existe des tas de solutions différentes avec des approches différentes. Dès lors, comment une seule spécification, ou devrais-je dire un seul élément, parviendrait-il à remplacer ce panorama de solutions ?

IV-B. Parce qu'il faut les mettre dans une case

La réponse à la question précédente est très simple : il n'y parviendra pas. Et il n'a jamais été question dans la spécification de ne serait-ce qu'essayer d'arriver à la cheville d'une solution de templating existante aujourd'hui. Je pense que l'introduction de la balise <template> répond bêtement au besoin de mettre le templating client dans une case ; comme s'il fallait sous-entendre son existence d'une quelconque manière dans une section de la spécification HTML.

Une case ou plutôt une boîte noire. En effet, pour essayer de convenir au plus grand nombre de méthodes de templating, les auteurs de la spécification ont voulu que le contenu HTML dans cet élément soit totalement inerte. Ainsi, il n'interfère pas avec le reste du document tant qu'il n'a pas été activé en JavaScript ; on laissera le soin à chaque bibliothèque de templating de l'activer au moment désiré et de la manière qui lui sied.

En nommant cet élément <template>, on peut légitimement dire qu'il y a tromperie sur la marchandise. Ne cherchez pas comment vous pouvez vous servir de cet élément pour concrètement écrire des templates. Cet élément ne fait rien de base, même pas d'interpolation de données ! Aucune instruction logique, aucune référence à un modèle de données. Rien de tout ça. C'est une boîte vide.

En réalité, cet élément est là uniquement pour remplacer le point d'ancrage des templates des solutions existantes qui est généralement une balise <script> avec un type inconnu du navigateur pour l'empêcher de tenter de l'interpréter :

Exemple d'élément déclaratif de template avec la bibliothèque Handlebars
Sélectionnez
<script id="mon-template" type="text/x-handlebars-template">

Il ne remplace donc absolument pas toutes les bibliothèques de templating existantes, contrairement à ce que le nom de l'élément pourrait laisser supposer. Cela a laissé perplexe beaucoup de gens, et certains participants à l'élaboration de cette spécification regrettent ce nommage :

C:\Article_Dvp\documents\web-components-debat\images\tweet-template-tag.png
Traduction : j'ai le sentiment que nous aurions dû appeler cet élément <inert> au lieu de <template>.

IV-C. Une utopie de standard

Pour essayer de convenir à toutes les approches, la spécification a opté pour en faire le moins possible ; à vrai dire presque rien. Mais le peu qu'elle fait sort déjà du cadre de certaines solutions de templating, notamment celles qui viennent s'interfacer sur des éléments du DOM déjà actifs dans le document avant le rendu du template. On peut aussi se demander comment cette spécification va permettre de gérer les états, les saisies formulaire, la compression ou précompilation des templates, les instructions logiques avancées qui influent sur la structure du DOM... Autant de questions déjà traitées par les bibliothèques de templating, mais auxquelles cette spécification n'apporte aucune réponse.

Le rafraichissement partiel de templates pose également problème. Prenons l'exemple d'un template qui affiche une liste d'articles. À la suite de l'ajout d'un article, nous souhaitons actualiser la vue en insérant uniquement l'élément du nouvel article, sans toucher aux autres. Or la référence logique à la boucle se trouve en principe dans le template, et non dans le DOM déjà généré. Il faut donc soit employer une méthode alternative de rendu pour les rafraichissements partiels, soit travailler sur un mécanisme de comparaison pour actualiser uniquement les parties du DOM ayant changé. Ce mécanisme, aussi appelé dirty-checking, est utilisé par plusieurs solutions complexes (notamment AngularJS, mais s'avère très consommateur de ressources.

De manière plus générale, il semble que le concept de templates statiques déclarés individuellement soit déjà dépassé comparé aux approches modernes dites de data-binding. On ne travaille plus avec des templates isolés, mais avec un ensemble de liens données/vue permettant un rafraîchissement intelligent et autonome. C'est pourquoi je doute qu'AngularJS évolue pour reposer sur cet élément <template> qui s'intègre assez mal avec le fonctionnement existant. Je n'irais pas jusqu'à dire que cette spécification est mort-née, mais son usage est certainement bien plus minoritaire qu'elle ne l'a laissé supposer.

V. Des mauvaises utilisations des Web Components

Suite à tous les défauts évoqués, parcourons divers exemples existants qui les mettent en évidence :

V-A. Le Web Component minimaliste

Un Web Component dont le code est bien trop simple pour justifier sa déclaration comme composant, ou qui ne s'utilise qu'une seule fois.

Exemples :

https://github.com/zenorocha/facebook-button

https://github.com/cesarwbr/google-analytics-element

V-B. Le Web-Component tout-en-un

Quand on s'amuse à mettre tout le contenu de son site web dans un seul élément parce que c'est cool, ou que l'on cherche à mettre des Web Components à l'intérieur d'un Web Component…

Exemple : https://github.com/faunt/domrgn

V-C. Le Web Component boîte noire ou iframe 2.0

Un Web Component que l'on pourrait aisément remplacer par un iframe tout en réduisant le risque de failles de sécurité. Souvent, il s'agit d'un composant qui charge de multiples scripts externes, avec un code difficile à analyser, très peu de contrôle sur le code importé et pouvant contenir d'éventuelles failles XSS. Il peut aussi s'agir d'un service Web notoire qui vient s'installer de manière un peu trop intrusive sur votre site web en chargeant de grosses API propres au fonctionnement du service (ce que les entreprises appellent parfois « SDK JavaScript », quoi que cela veuille dire).

Exemple : http://component.kitchen/components/google-map

C:\Article_Dvp\documents\web-components-debat\images\google-web-components.png
Si vous utilisez un Web Component externe, pensez toujours à regarder dans la boîte.

V-D. Le Web Component anti-standard

Un Web-Component qui reprend le fonctionnel d'un standard existant sans utiliser ce standard, ou qui pourrait être remplacé par un polyfill.

Exemples :

http://garstasio.github.io/file-input/components/file-input/

http://bosonic.github.io/elements.html#b-datepicker

V-E. Le Web Component qui n'a rien à faire dans HTML

Un Web Component qui ne représente pas d'élément, qui n'est pas identifiable visuellement ou qui ne présente aucun sens sémantique dans le document et peut être remplacé par un script explicite.

Exemple : http://www.polymer-project.org/docs/elements/core-elements.html#core-ajax

V-F. Le Web Component gadget

Un Web Component qui n'a aucune raison d'exister, mais qui existe ; pour le fun, pour la publicité ou simplement parce qu'on peut le faire. Le point préoccupant est que ces gadgets se retrouvent au même plan que d'autres composants « sérieux » dans les sites les référençant. Cela amène la question de comment s'assurer de la qualité et de la pérennité des composants trouvés sur le net.

Exemples :

https://github.com/passy/x-pokemon

https://github.com/beldar/boris-bikes

VI. Conclusion

J'ai utilisé l'humour et un ton assez provocateur dans cet article pour mettre en exergue les défauts des Web Components. Même si certains aspects de la spécification sont à revoir complètement selon moi, tout n'est pas à jeter. Je pense que tous les articles et vidéos déjà parus sur le sujet ont bien expliqué en large et en travers les avantages des Web Components, c'est pourquoi je me suis concentré sur le négatif ici.

Les Web Components, lorsqu'ils sont correctement utilisés, apportent une meilleure lisibilité dans les pages HTML comportant beaucoup d'éléments d'interface sophistiqués (ce qu'on pourrait typiquement appeler les web-apps). Ils permettent de modulariser le HTML, de faciliter la maintenance du code et de réduire le risque d'effets de bord et de régressions fonctionnelles grâce à l'isolation apportée par les fragments de document.

Toutefois, il n'y a pas d'alternative avec les éléments standardisés du HTML. Bien qu'il s'utilise au même niveau qu'un élément HTML, un Web Component est un enrobage autour d'un ou plusieurs éléments accompagnés de CSS et de JavaScript. Il vaut toujours mieux privilégier l'élément standard adéquat plutôt que de vouloir redéfinir les propriétés et le comportement d'éléments neutres tels que <div> ou <span> pour arriver à l'objectif désiré (rappelez-vous l'exemple du datepicker). En effet, les propriétés du composant se limitent au périmètre envisagé par son développeur, contrairement aux éléments standards qui sont adaptés nativement selon le navigateur et le terminal. Ces adaptations ont déjà montré leur utilité par le passé, notamment pour les navigateurs mobiles des premiers smartphones. Il est très difficile (impossible ?) pour un développeur de couvrir tous les contextes d'utilisation existants aujourd'hui, sans même envisager ceux de demain. Et si on y consacrait plus d'efforts, la taille du code des composants en accuserait le coup.

Ainsi, pour savoir s'il est légitime de définir un Web Component pour un besoin donné, voilà ce qu'un « bon » Web Component doit présenter comme caractéristiques selon moi :

  • Il n'existe aucun élément standard ou en cours de standardisation qui puisse répondre à ce besoin.
  • Il remplit bien la fonction d'élément : il peut être identifié visuellement et placé dans la hiérarchie du document le contenant.
  • Il est paramétrable dans une certaine mesure : s'il devient trop complexe, il est sans doute décomposable en plusieurs composants.
  • Il est réutilisable, y compris à plusieurs endroits d'un même document.
  • Il ne dépend pas du HTML parent dans lequel il se trouve.
  • Il est autonome (pas de chargement de scripts externes).
  • Il est adapté à un maximum de terminaux (tailles d'écran, interfaces souris/tactile, etc.).
  • Il est adapté à un maximum d'utilisateurs (efforts sur l'accessibilité et le contexte d'utilisation).
  • Il ne laisse pas de traces mémoire JavaScript une fois l'élément supprimé.
  • Son code est lisible et ne laisse planer aucun doute sur son fonctionnement interne.

La publication et le référencement d'un catalogue de web components est une idée très séduisante aux yeux de nombreux développeurs, et plusieurs sites sont déjà à l'œuvre : http://component.kitchen/, http://customelements.io/). Néanmoins, il convient de prendre garde à la qualité et à la pertinence de ces composants : faites le tour des différents composants déjà proposés dans ces catalogues et vous vous apercevrez que bien peu d'entre eux respectent toutes les caractéristiques précédemment listées.

En résumé, les Web Components sont un progrès car ils normalisent la définition et l'intégration de composants d'interface, sans toutefois révolutionner leur nature elle-même. Cependant, chaque progrès doit être utilisé intelligemment et modérément. Les composants sont des boîtes noires qui peuvent dissimuler un code de mauvaise qualité, des risques de sécurité, des défauts d'accessibilité ou des actions trop intrusives sur le reste de la page. Les sites de référencement des Web Components devront ainsi privilégier la qualité sur la quantité si l'on souhaite que le Web soit bâti avec des briques solides.

VII. Remerciements

Un grand merci à  Tarh_ pour sa relecture technique et ses remarques très pertinentes, ainsi qu'à f-leb pour sa relecture orthographique de qualité.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Copyright © 2014 Sylvain Pollet-Villard. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.