Salut et bienvenue dans cette nouvelle série de vidéos consacrée aux technologies que je n'utilise plus. Il y a de nombreuses technologies que j'ai abordées sur cette chaîne, pour lesquelles j'ai parfois créé des formations, mais que j'ai arrêté de traiter du jour au lendemain. J'ai donc pensé qu'il serait intéressant de vous offrir une conclusion pour ces technologies et de vous expliquer à chaque fois pourquoi je ne les utilise plus et pourquoi je ne continue pas d'en parler. Aujourd'hui, nous commençons cette série avec Vue.js, une librairie que j'ai beaucoup couvert sur cette chaîne avec notamment une formation sur Vue.js 2.
Cependant, avant de plonger dans le vif du sujet, je tiens à souligner que ce que je vais partager ici est subjectif. Les points que je considère comme problématiques le sont pour moi et moi seul. Ne prenez pas cette vidéo comme une critique de Vue.js, et ne la partagez pas cet article pour dissuader quelqu'un de l'utiliser. Ce que je vais expliquer ici concerne ma propre sensibilité et les raisons pour lesquelles la librairie ne me convient plus aujourd'hui, mais cela ne signifie en aucun cas que Vue.js est un mauvais outil. Si vous vous en sortez bien avec et que son approche vous convient, c'est un excellent choix.
Lorsque j'ai commencé à faire de plus en plus de front-end, je me suis orienté vers AngularJS qui me permettait de créer des interfaces complexes avec une approche relativement simple par rapport à ce que l'on avait avant (BackboneJS).
<!-- Exemple de compteur avec AngularJS -->
<div ng-controller="CounterController">
<button ng-click="increment()">Incrémenter</button>
<p>Compteur : {{ count }}</p>
</div>
<script>
angular.module('myApp', [])
.controller('CounterController', function($scope) {
$scope.count = 0;
$scope.increment = function() {
$scope.count++;
};
});
</script>
Même si mon expérience initiale était positive lorsque les projets devenaient complexes, AngularJS montrait rapidement ses limites (aussi bien en terme d'organisation qu'en terme de performance). Malheureusement les problèmes ne pouvaient pas être corrigé sans un changement profond du fonctionnement du Framework et c'est pourquoi la version 2 (nommé simplement Angular) a été une réécriture complète et un changement de fonctionnement important (AngularJS et Angular peuvent être considéré comme 2 frameworks complètements différents).
En parallèle, React a également gagné en popularité en étant la librairie derrière le front de Facebook. Malheureusement, mon premier contact avec React n'a pas été convaincant. Je trouvais les classes compliquées à utiliser et le JSX peu pratique. Heureusement, Vue.js est apparu sur mes radars et son approche m'a tout de suite plus convaincu. Écrire des composants était simple, et l'approche était similaire à ce que j'avais aimé avec AngularJS. J'ai donc adopté Vue.js comme librairie principale et c'est à cette époque que vous avez eu droit a pas mal de contenu sur Vue.js.
<!-- Exemple de compteur avec VueJS -->
<div id="app">
<button @click="increment">Incrémenter</button>
<p>Compteur : {{ count }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
increment: function() {
this.count++;
}
}
});
</script>
En 2019, React a introduit les Hooks, une nouvelle façon de créer des composants. Cette approche a pas mal divisé la communauté initialement par son approche assez différente de ce que l'on a l'habitude de voir. J'étais plutôt dans le camps des sceptique même si le bénéfice sur l'organisation était indéniable. Il m'aura donc fallu un temps avant d'accepter d'essayer cette approche et après avoir passé une phase de découverte un peu complexe j'ai été convaincu par les bénéfice de cette approche et j'ai commencé à apprécier React.
De son côté Vue.js répondra à l'apparition des hooks avec la création de l'API Composition lors de la sortie de sa version 3.0, version qui introduira aussi le support du langage TypeScript.
Maintenant, passons aux problèmes que je rencontre avec Vue.js.
Le premier problème que j'ai avec Vue.js concerne l'utilisation des fichiers .vue
. L'utilisation d'une extension et d'une structure propre à la librairie nécessite des outils spécifiques pour l'édition, le formatage, la vérification du code, etc. Cela complique l'expérience de développement, et le support varie d'un éditeur à l'autre. Par exemple, dans mon cas, certaines fonctionnalités fonctionnent bien dans Visual Studio Code mais pas dans PHPStorm, car les plugins n'ont pas forcément le même niveau de support.
Alors je sais, certains me diront
ouais mais attends, tu es en train de te moquer de nous parce que finalement avec React par exemple on a la même problématique avec le JSX et le TSX
La particularité c'est que là où React a été intelligent, c'est que la syntaxe est indépendante de la librairie et le JSX peut être utilisé pour autre chose que React (c'est ce qui permet par exemple à Preact d'exister, mais il est possible de créer sa propre fonction JSX). L'autre particularité c'est que le JSX n'est conçu que comme une petite évolution du JavaScript en ajoutant un seul élément de syntaxe. Ces 2 points a permis à la syntaxe une plus large adoption et on se retrouve aujourd'hui avec des outils qui supportent nativement le JSX ce qui limite la friction si on compare au support des fichiers .vue.
Ensuite, Vue.js impose la création d'un seul composant par fichier, ce qui rend l'organisation plus difficile. Parfois on a besoin d'introduire un tout petit composant pour morceler la logique et cela nécessite la création d'un nouveau fichier .vue. Cela me pose 2 problèmes principaux :
Avec React, vu qu'un composant n'est qu'une fonction qui renvoie un noeud JSX je peux facilement morceler mon code pour séparer la logique réutilisable.
L'API composition est la réponse de Vue.js à l'apparition des hooks et permet de séparer la logique des composants. Par exemple, si je souhaite suivre la position du curseur je peux abstraire ça dans une fonction spéciale et l'utiliser dans n'importe quel composant.
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
Malheureusement, cette nouvelle approche vient ajouter une complexité à Vue.js car il faut faire attention et différencier une valeur réactive d'une valeur classique.
<script setup lang="ts">
import { toRefs, computed } from 'vue';
const props = defineProps<{count: number}>()
const count = props.count // Pas réactif
const countComputed = computed(() => props.count) // Réactif
const countToRefs = toRefs(props).count // Réactif
</script>
<template>
<p>Props: {{ props.count > 0 ? 'positif' : 'négatif' }}</p>
<p>Destructure: {{ count > 0 ? 'positif' : 'négatif' }}</p>
<p>Computed: {{ countComputed > 0 ? 'positif' : 'négatif' }}</p>
<p>toRefs: {{ countToRefs > 0 ? 'positif' : 'négatif' }}</p>
</template>
Les choses peuvent rapidement devenir complexe lorsque l'on travaille avec des objets car il faut savoir ce qui est réactif :
value
props
par exemple on n'utilise pas value
). Mais les propriétés elles ne sont pas réactive.De mon côté cela me force en permanence à réfléchir aux variables que je manipule et même si TypeScript aide grandement à capturer les erreurs il n'est pas rare que cette distinction entre réactif / non réactif soit la source de pas mal de problèmes lorsque je travaille avec Vue.js 3.
Même si cela fait un moment que le VirtualDOM existe je ne suis pas totalement convaincu que cela soit l'approche la plus adaptée en terme de performance (comparer tout un arbre à chaque changement d'état me semble être une source de gaspillage) mais je conçois les bénéfices en terme d'abstraction apportée par cette méthode. Avec le Virtual DOM on peut séparer la logique de la librairie de la cible visée ce qui permet son utilisation en dehors du DOM.
Le problème avec Vue.js est que ce Virtual DOM n'est pas exposé à l'utilisateur et n'est utilisé qu'en interne lors de la conversion des fichiers .vue
en fichier JavaScript. Cette compilation permet à Vue.js d'optimiser les performances de rendu en suivant les dépendances associées à chaque nœud. Mais en n'ayant pas la main sur cette fonction de rendu cela réduit les possibilités au niveau du code et on ne bénéficie pas de tous les atouts du Virtual DOM (pouvoir par exemple manipuler le Virtual dom depuis une fonction, faire des composants d'ordre supérieur facilement) et la complexité est déplacée vers le template.
On notera d'ailleurs que Vue.js travaille sur une expérimentation, nommée "vapor", qui se passerait du VirtualDOM au profit de manipulation direct du DOM comme le fait Svelte ou SolidJS avec
Enfin, l'écosystème JavaScript a beaucoup évolué et de nouvelles propositions sont apparues, propositions qui résonnent plus avec ce qui m'avait plu à l'origine avec Vue.js. Par exemple, je trouve que Svelte est une proposition plus intéressante en terme de simplicité (même si la version 5 risque de changer les choses).
Mais voilà pour les points qui sont bloquants pour moi et qui font que Vue.js ne me convient plus. Comme vous l'avez vu, ce ne sont pas des points qui sont rédhibitoire, ça ne va pas m'empêcher d'utiliser Vue.js quand un client me le demande. En revanche, quand je dois faire un choix de framework, j'ai tendance à aller plutôt vers du React qui a une syntaxe et une logique qui me parle plus (et qui a aussi son lot d'inconvénients, mais des inconvénients qui sont à mon sens moins dérangeants que ceux de Vue.js pour moi).
Après il ne faut jamais dire jamais, c'est-à-dire que là j'ai cette opinion et cet avis vis-à-vis de la version de Vue.js à l'heure actuelle et vis-à-vis de l'écosystème. Peut-être que mes préférences vont évoluer ou aussi le framework peut évoluer dans un bon sens et je peux peut-être être amené à le réutiliser dans un futur plus ou moins lointain. Cependant, à l'heure actuelle, je ne compte pas forcément continuer à l'utiliser, donc si vous ne voyez pas de nouvelles vidéos sur Vue.js, c'est tout à fait normal, c'est parce que ce n'est plus un framework que j'utilise au quotidien. J'espère que ça vous permettra d'avoir une sorte de fermeture, de fin à cette arc Vue.js et je vous donne rendez-vous dans une prochaine vidéo.