Migrer Puppeteer vers TypeScript

Jack Franklin
Jack Franklin

Nous sommes très inconditionnels de TypeScript dans l'équipe DevTools, à tel point qu'un nouveau code dans les outils de développement y est créé et que nous sommes en train de migrer l'ensemble du codebase afin qu'il soit vérifié par TypeScript. Vous trouverez plus d'informations sur cette migration dans notre conférence du Sommet des développeurs Chrome 2020. Par conséquent, il était parfaitement logique d'envisager également la migration du codebase de Puppeteer vers TypeScript.

Planifier la migration

Au moment de planifier notre migration, nous voulions pouvoir avancer par petites étapes. Cela permet de réduire les frais généraux de la migration (vous ne travaillez à tout moment que sur une petite partie du code) et de limiter les risques. En cas de problème au cours de l'une de ces étapes, vous pouvez facilement l'annuler. Puppeteer compte de nombreux utilisateurs et une version défectueuse causerait des problèmes à un grand nombre d'entre eux. Il était donc essentiel de limiter au minimum le risque de dysfonctionnement des modifications.

Nous sommes également ravis d'avoir mis en place un ensemble complet de tests unitaires couvrant l'ensemble des fonctionnalités de Puppeteer. Ainsi, nous avons pu être sûrs que nous ne détruisions pas le code lors de la migration, mais aussi que nous n'apportions pas de modifications à notre API. Le but de la migration était de la terminer sans même que les utilisateurs de Puppeteer se rendent compte que nous l'avions migré. Les tests ont joué un rôle essentiel dans cette stratégie. Si nous n'avions pas eu une bonne couverture de test, nous l'aurions ajouté avant de poursuivre la migration.

Il est risqué d'apporter des modifications au code sans effectuer de tests. En revanche, les modifications impliquant des fichiers entiers ou l'intégralité du codebase sont particulièrement risquées. Lorsque vous apportez des modifications mécaniques, il est facile de passer à côté d'une étape. À plusieurs reprises, les tests ont détecté un problème qui avait passé outre le responsable de la mise en œuvre et le réviseur.

Nous avons notamment consacré du temps à la configuration de l'intégration continue (CI). Nous avons remarqué que les exécutions CI sur les demandes d'extraction étaient irrégulières et échouaient souvent. Cela se produisait si souvent que nous avions pris l'habitude d'ignorer notre CI et de fusionner les demandes d'extraction de toute façon, en supposant que l'échec était un problème ponctuel sur CI plutôt que sur un problème dans Puppeteer.

Après une maintenance générale et du temps consacré à la correction de certains "éclats de test" réguliers, nous avons réussi à le passer de manière beaucoup plus cohérente, ce qui nous permet d'écouter la CI et de savoir qu'une défaillance indiquait un problème réel. Ce travail n'est pas glamour et il est frustrant de voir les exécutions CI sans fin. Toutefois, il était essentiel que notre suite de tests s'exécute de manière fiable, compte tenu du nombre de demandes d'extraction générées par la migration.

Sélectionner un fichier et le déplacer

À ce stade, nous avions préparé notre migration et un serveur CI robuste rempli de tests pour surveiller nos arrières. Plutôt que d'explorer un fichier arbitraire, nous avons volontairement choisi un petit fichier à migrer. Il s'agit d'un exercice utile car il vous permet de valider le processus planifié que vous êtes sur le point d'entreprendre. Si elle fonctionne sur ce fichier, votre approche est valide ; si ce n'est pas le cas, vous pouvez revenir à la planche à dessin.

De plus, le fait d'effectuer le transfert fichier par fichier (et avec les versions standards de Puppeteer, de sorte que toutes les modifications n'étaient pas disponibles dans la même version npm) a permis de limiter les risques. Nous avons choisi DeviceDescriptors.js comme premier fichier, car il s'agit de l'un des fichiers les plus simples du codebase. Cela peut sembler un peu décevant de faire tout ce travail de préparation et d'aboutir à un si petit changement, mais l'objectif n'est pas d'apporter d'importants changements immédiatement, mais d'agir avec prudence et méthodiquement fichier par fichier. Le temps passé à valider l'approche vous fait gagner du temps lors de la migration, lorsque vous rencontrez des fichiers plus complexes.

Démontrer le modèle et répéter

Heureusement, la modification de DeviceDescriptors.js a bien été effectuée dans le codebase, et le plan a fonctionné comme nous l'espérions. À ce stade, vous pouvez vous attarder et vous lancer, et c'est exactement ce que nous avons fait. L'utilisation d'une étiquette GitHub est un très bon moyen de regrouper toutes les requêtes d'extraction, et nous avons trouvé cela utile pour suivre la progression.

Migrer et améliorer le service plus tard

Pour tout fichier JavaScript individuel, notre processus était le suivant:

  1. Renommez le fichier .js en .ts.
  2. Exécutez le compilateur TypeScript.
  3. Corrigez les éventuels problèmes.
  4. Créez la requête d'extraction.

La majeure partie du travail de ces demandes d'extraction initiales consistait à extraire les interfaces TypeScript pour les structures de données existantes. Dans le cas de la première demande d'extraction ayant migré DeviceDescriptors.js dont nous avons discuté précédemment, le code provient de:

module.exports = [
  { 
    name: 'Pixel 4',
    … // Other fields omitted to save space
  }, 
  …
]

Et devient:

interface Device {
  name: string,
  …
}

const devices: Device[] = [{name: 'Pixel 4', …}, …]

module.exports = devices;

Dans le cadre de ce processus, nous avons passé en revue chaque ligne du codebase à la recherche de problèmes. Comme pour tout codebase qui existe depuis quelques années et s'est développé au fil du temps, il existe des domaines où il est possible de refactoriser le code et d'améliorer la situation. Surtout avec le passage à TypeScript, nous avons vu où une légère restructuration du code nous permettrait de nous appuyer davantage sur le compilateur et d'améliorer la sûreté du typage.

Contrairement à l'intuition, il est très important de rester à l'idée d'effectuer immédiatement ces changements. L'objectif de la migration est de convertir le codebase en TypeScript. Lors d'une migration de grande envergure, vous devez toujours réfléchir au risque de causer des dysfonctionnements dans le logiciel et pour vos utilisateurs. En réduisant au maximum les modifications initiales, nous avons gardé ce risque faible. Une fois le fichier fusionné et migré vers TypeScript, nous avons pu apporter des modifications de suivi afin d'améliorer le code afin d'exploiter le système de types. Veillez à définir des limites strictes pour votre migration et essayez de les respecter.

Migrer les tests pour tester nos définitions de type

Après avoir migré l'intégralité du code source vers TypeScript, nous avons pu nous concentrer sur les tests. Nos tests ont permis d'obtenir une excellente couverture, mais ils ont tous été écrits en JavaScript. Cela signifiait que la chose qu'ils n'avait pas testée était nos définitions de type. L'un des objectifs à long terme du projet (sur lequel nous travaillons encore) est d'envoyer des définitions de type de haute qualité prêtes à l'emploi avec Puppeteer, mais nous n'avions aucune vérification dans notre codebase concernant nos définitions de type.

En migrant les tests vers TypeScript (en suivant le même processus, en passant fichier par fichier), nous avons identifié des problèmes avec TypeScript, qui auraient été laissés aux utilisateurs autrement. Désormais, nos tests couvrent non seulement l'ensemble de nos fonctionnalités, mais servent également de contrôle qualité pour TypeScript.

En tant qu'ingénieurs travaillant sur le codebase Puppeteer, nous avons grandement profité de TypeScript. Associé à notre environnement CI beaucoup plus amélioré, il nous a permis de gagner en productivité lorsque nous travaillions sur Puppeteer et de détecter les bugs qui, autrement, auraient fait l'objet d'une version npm. Nous sommes ravis de recevoir des définitions TypeScript de haute qualité, afin que tous les développeurs utilisant Puppeteer puissent bénéficier de ce travail.

Télécharger les canaux de prévisualisation

Nous vous conseillons d'utiliser Chrome Canary, Dev ou Beta comme navigateur de développement par défaut. Ces versions preview vous permettent d'accéder aux dernières fonctionnalités des outils de développement, de tester des API de pointe de plates-formes Web et de détecter les problèmes sur votre site avant même que vos utilisateurs ne le fassent.

Contacter l'équipe des outils pour les développeurs Chrome

Utilisez les options suivantes pour discuter des nouvelles fonctionnalités et des modifications dans le message, ou de tout autre sujet lié aux outils de développement.

  • Envoyez-nous une suggestion ou des commentaires via crbug.com.
  • Signalez un problème lié aux outils de développement en accédant à Plus d'options   More > Aide > Signaler un problème dans les outils de développement.
  • Envoyez un tweet à @ChromeDevTools.
  • Laissez des commentaires sur les nouveautés des outils de développement vidéos YouTube ou les vidéos YouTube de nos conseils sur les outils de développement.