Semaine 3 – Prise en charge de @embroider/webpack
#web #emberjs #codemod #embroider #vite #vitest #testem #concurrency
À la fin de cette troisième semaine, ember-vite-codemod permet d’intégrer Vite à votre application Ember, auparavant construite avec @embroider/webpack, et ce cas est désormais testé par la CI, ce qui est la partie la plus importante.
De @embroider/webpack à @embroider/vite : aussi simple que ça ? #
Au moment où j’écris ces lignes, le README d’Embroider explique comment commencer à builder une application classique avec @embroider/webpack ; et c’est assez simple, le seul fichier qui change est ember-cli-build.js.
C’est une excellente nouvelle pour notre codemod, car ember-cli-build.js s’avère être le seul fichier nécessitant des ajustements pour supporter une migration depuis @embroider/webpack. En d’autres termes, la partie difficile est déjà faite : une fois que ember-cli-build.js peut être géré à la fois comme “je pars d’une application classique” et “je pars d’Embroider+Webpack”, le reste du codemod fonctionne exactement comme avant.
Pour gérer ça, j’ai introduit une nouvelle option : --embroider-webpack. Elle permet au codemod de comprendre la situation initiale plutôt que d’essayer de la détecter d’une manière ou d’une autre. La PR adapte également la documentation en conséquence.
Aussi simple que ça ? Pas tout à fait. Si j’ai passé une demi-journée sur l’implémentation elle-même, les tests ont été plus difficiles à gérer.
Testception #
Port 7357 already in use :need-a-sad-hamster-emoji: #
Le défi le plus intéressant de cette semaine a été de se faire une bonne représentation mentale des tests d’ember-vite-codemod. L’erreur à laquelle j’ai dû faire face était “port 7357 already in use”. Ça signifie que j’instancie un serveur sur un port déjà utilisé par un autre serveur en cours d’exécution. Mais pourquoi cela arrive-t-il ?
Si vous connaissez l’écosystème Ember, vous avez peut-être reconnu ce numéro de port : c’est le port par défaut de Testem ! Mais pourquoi aurais-je plusieurs serveurs Testem écoutant en même temps ? C’est essentiellement une histoire de concurrence, mais pour la comprendre clairement, il faut bien visualiser l’exécution des tests.
Ce que font les tests #
Nous avons trois tests : un pour Ember classique (dernière version), un pour Ember classique 5.12, et un pour Embroider+Webpack Ember (dernière version). Ces tests font exactement la même chose pour chaque version. En gros :
- Générer une application Ember avec
ember new - Créer un test d’acceptation simple qui visite la page d’accueil
- Construire l’application à l’ancienne (ember-cli + Broccoli)
- Exécuter les tests (
ember test) pour s’assurer que le test d’acceptance passe dès le départ - Exécuter le codemod
- Reconstruire l’application (elle utilise maintenant Vite)
- Exécuter les tests une fois de plus pour s’assurer qu’ils passent avec le mode build de Vite
- Démarrer un serveur de développement Vite
- Exécuter les tests une dernière fois avec Testem pour vérifier qu’ils passent avec le mode dev de Vite
Le point important à retenir est que nous avons un test, et une partie de ses instructions consiste à exécuter les tests d’une application. Des tests dans des tests. De la testception.
Les tests d’ember-vite-codemod s’exécutent avec Vitest. Imaginez trois boîtes : chaque boîte représente un test exécuté par Vitest, “classique dernière version”, “classique 5.12”, “Embroider+Webpack dernière version”. Lorsque les tests sont dans le même fichier, ils s’exécutent séquentiellement par défaut. Mais lorsqu’ils sont dans des fichiers différents, ils s’exécutent en parallèle par défaut. Au début, mon nouveau test “Embroider+Webpack dernière version” était exécuté dans un fichier séparé, tandis que les deux tests classiques étaient dans le même fichier.
Maintenant, dans chaque boîte, imaginez trois autres boîtes de tests s’exécutant séquentiellement : d’abord “application legacy”, puis “application Vite en mode build”, puis “application Vite en mode dev” ; et ces tests sont des tests Ember, ce qui signifie qu’ils reposent sur Testem.
En résumé, j’ai deux fichiers de test Vitest qui s’exécutent simultanément, et les deux tests qu’ils exécutent tentent d’instancier un serveur Testem. Le plus rapide y parvient ; le second déclenche un “port 7357 déjà utilisé”.
De ce point de vue, Vitest est plus intelligent que Testem : il peut trouver des ports disponibles pour gérer la concurrence. Testem, en revanche, reste sur son port par défaut si vous ne spécifiez pas explicitement un autre port. La suite de l’histoire est un peu moins intéressante à mon avis. J’ai essayé d’utiliser portfinder pour résoudre le problème, mais au moment où le premier serveur avait démarré, portfinder avait déjà retourné le même numéro de port au second. Finalement, j’ai trouvé un moyen de spécifier moi-même les ports avec un numéro incrémental.
Concurrence : faire en sorte que ça fonctionne #
Ma solution finale a été de regrouper tous les tests dans un seul fichier (après plusieurs niveaux d’abstraction, un seul fichier était plus élégant), et j’ai exécuté les trois tests simultanément en utilisant it.concurrent de l’API Vitest. Chaque test utilise Testem avec un port différent, spécifié explicitement par un numéro incrémental.
Faire fonctionner la concurrence dans une telle suite de tests est important, car chaque test est assez lourd : il génère une application Ember, ajuste ses dépendances, la build et exécute les tests plusieurs fois. Lorsque j’exécute les tests séquentiellement sur mon MacBook à ce stade du projet, cela prend environ 1'30~2'00 minutes par test, soit 5 minutes pour les trois. Avec la concurrence, une minute est déjà économisée. Comme nous voulons activer les tests pour de nombreuses autres versions d’Ember et idéalement ajouter plus de tests unitaires pour les scripts de transformation, bien gérer la concurrence sur notre CI n’est pas une option.
Ce fut une semaine courte pour moi (seulement trois jours de travail), mais je suis très satisfaite du résultat : le codemod prend désormais en charge la migration depuis @embroider/webpack, et j’ai maintenant une image mentale claire de ce que fait la CI. Chris Manson travaille actuellement à faire fonctionner Vite pour Ember < 5.12 (ce qui implique qu’Embroider effectue des correctifs sur ember-source lui-même) ; ce n’est que lorsqu’il aura terminé que ça aura du sens pour notre codemod de supporter ces versions plus anciennes. En attendant, même si nous pourrions améliorer le codemod indéfiniment, nous devons également nous occuper du reste des tâches prévues pour le premier trimestre. Je pense qu’il est temps pour moi de m’attaquer à l’audit des 100 % des addons Ember les plus populaires pour avoir une idée de l’état de la communauté sur ce sujet.