Migrazione di Puppeteer a TypeScript

Nel team di DevTools siamo grandi fan di TypeScript, al punto che il nuovo codice in DevTools viene creato in questo linguaggio e siamo nel bel mezzo di una grande migrazione dell'intero codice di base al controllo dei tipi da parte di TypeScript. Puoi scoprire di più su questa migrazione nel nostro intervento al Chrome Dev Summit 2020. Per questo motivo era perfettamente logico anche prendere in considerazione la migrazione del codebase di Pupeteer a TypeScript.

Pianificazione della migrazione

Quando abbiamo pianificato la migrazione, volevamo essere in grado di fare progressi a piccoli passi. In questo modo, riduci l'overhead della migrazione, perché lavori solo su una piccola parte del codice alla volta, e riduci anche il rischio. Se si verificano problemi con uno dei passaggi, puoi facilmente ripristinarlo. Puppeteer ha molti utenti e una release non funzionante potrebbe causare problemi a molti di loro, quindi era fondamentale ridurre al minimo il rischio di interrompere le modifiche.

Inoltre, abbiamo avuto la fortuna che Puppeteer dispone di un solido insieme di test di unità che coprono tutte le sue funzionalità. Ciò significava che potevamo essere certi di non interrompere il codice durante la migrazione, ma anche di non introdurre modifiche alla nostra API. L'obiettivo della migrazione era completarla senza che gli utenti di Puppeteer si accorgessero nemmeno che era stata eseguita e i test erano una parte fondamentale di questa strategia. Se non avessimo avuto una buona copertura dei test, lo avremmo aggiunto prima di continuare con la migrazione.

Eseguire qualsiasi modifica al codice senza test è rischioso, ma le modifiche che interessano interi file o l'intera base di codice sono particolarmente rischiose. Quando apporti modifiche meccaniche, è facile saltare un passaggio e, in più occasioni, i test hanno rilevato un problema che era sfuggito sia all'implementatore sia al revisore.

Una cosa su cui abbiamo investito il tempo in anticipo è stata la nostra configurazione di integrazione continua (CI). Abbiamo notato che le esecuzioni di CI sulle richieste di pull erano instabili e spesso non riuscite. Questo accadeva così spesso che avevamo preso l'abitudine di ignorare il nostro sistema di CI e di unire comunque le richieste pull, assumendo che l'errore fosse un problema una tantum del sistema di CI anziché un problema di Puppeteer.

Dopo un po' di manutenzione generale e tempo dedicato alla correzione di alcuni regolari risvolti di test, abbiamo raggiunto uno stato di superamento molto più coerente, consentendoci di ascoltare la CI e sapere che un errore indicava un problema reale. Questo lavoro non è molto interessante ed è frustrante guardare esecuzioni CI infinite, ma era fondamentale avere la nostra suite di test in esecuzione in modo affidabile, dato il numero di richieste pull generate dalla migrazione.

Scegliere e caricare un file

A questo punto, la migrazione era pronta e avevamo un solido server CI pieno di test per proteggerci. Anziché iniziare con un file qualsiasi, abbiamo scelto intenzionalmente un file di piccole dimensioni per la migrazione. Si tratta di un esercizio utile perché ti consente di convalidare il processo pianificato che stai per intraprendere. Se funziona con questo file, il tuo approccio è valido; in caso contrario, puoi tornare al tavolo da disegno.

Inoltre, l'approccio file per file (e le release regolari di Puppeteer, che hanno impedito che tutte le modifiche venissero rilasciate nella stessa versione di npm) ha ridotto il rischio. Abbiamo scelto DeviceDescriptors.js come primo file, perché era uno dei file più semplici nel codice di base. Può sembrare un po' deludente fare tutto questo lavoro di preparazione per una modifica così piccola, ma l'obiettivo non è apportare subito modifiche enormi, ma procedere con cautela e metodo, file per file. Il tempo dedicato alla convalida dell'approccio fa sicuramente risparmiare tempo nel corso della migrazione, quando si accede ai file più complicati.

Verifica il pattern e ripeti

Fortunatamente, la modifica a DeviceDescriptors.js è stata inserita correttamente nella base di codice e il piano ha funzionato come speravamo. A questo punto, puoi metterti al lavoro e procedere, proprio come abbiamo fatto noi. L'utilizzo di un'etichetta GitHub è un ottimo modo per raggruppare tutte le richieste di pull e lo abbiamo trovato utile per monitorare l'avanzamento.

Esegui la migrazione e migliorala in un secondo momento

Per ogni singolo file JavaScript, la nostra procedura è stata la seguente:

  1. Rinomina il file da .js a .ts.
  2. Esegui il compilatore TypeScript.
  3. Risolvi eventuali problemi.
  4. Crea la pull request.

La maggior parte del lavoro in queste richieste di pull iniziali è stato quello di estrarre le interfacce TypeScript per le strutture di dati esistenti. Nel caso della prima pull request che ha eseguito la migrazione di DeviceDescriptors.js di cui abbiamo discusso in precedenza, il codice è passato da:

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

e diventa:

interface Device {
  name: string,
  
}

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

module.exports = devices;

Questo processo prevedeva la necessità di esaminare ogni riga del codebase per individuare eventuali problemi. Come per qualsiasi base di codice esistente da alcuni anni e cresciuta nel tempo, esistono aree di opportunità per eseguire il refactoring del codice e migliorare la situazione. Soprattutto con il passaggio a TypeScript, abbiamo notato dei punti in cui una leggera ristrutturazione del codice ci avrebbe consentito di affidarci maggiormente al compilatore e migliorare la sicurezza del tipo.

In modo controintuitivo, è molto importante impedire di apportare subito queste modifiche. L'obiettivo della migrazione è portare il codebase in TypeScript e, in ogni momento di una migrazione di grandi dimensioni, dovresti pensare al rischio di causare danni al software e agli utenti. Mantenendo le modifiche iniziali minime, abbiamo ridotto al minimo il rischio. Una volta unito il file e eseguita la migrazione a TypeScript, abbiamo potuto apportare modifiche successive per migliorare il codice e sfruttare il sistema di tipi. Assicurati di impostare limiti rigidi per la migrazione e cerca di rispettarli.

Eseguire la migrazione dei test per testare le nostre definizioni di tipo

Una volta eseguita la migrazione dell'intero codice sorgente a TypeScript, abbiamo potuto concentrarci sui nostri test. I nostri test hanno avuto un'ampia copertura, ma erano tutti scritti in JavaScript. Ciò significa che una cosa che non hanno testato sono le nostre definizioni di tipo. Uno degli obiettivi a lungo termine del progetto (su cui stiamo ancora lavorando) è quello di fornire fin da subito definizioni dei tipi di alta qualità con Puppeteer, ma non abbiamo eseguito alcun controllo nel nostro codebase sulle definizioni dei tipi.

Eseguendo la migrazione dei test a TypeScript (seguendo la stessa procedura, file per file), abbiamo rilevato problemi con il nostro TypeScript che altrimenti sarebbero stati lasciati agli utenti. Ora i nostri test non solo coprono tutte le nostre funzionalità, ma fungono anche da controllo qualità del nostro TypeScript.

Abbiamo già tratto enormi vantaggi da TypeScript in qualità di ingegneri che lavorano sulla base di codice di Puppeteer. Insieme al nostro ambiente CI molto migliorato, ci ha permesso di diventare più produttivi quando lavoravamo su Puppeteer e di avere TypeScript rilevare bug che altrimenti sarebbero arrivati in una release npm. Siamo lieti di rilasciare definizioni TypeScript di alta qualità per consentire a tutti gli sviluppatori che utilizzano Puppeteer di trarre vantaggio da questo lavoro.

Scaricare i canali di anteprima

Valuta la possibilità di utilizzare Chrome Canary, Dev o Beta come browser di sviluppo predefinito. Questi canali di anteprima ti consentono di accedere alle funzionalità più recenti di DevTools, di testare API di piattaforme web all'avanguardia e di trovare i problemi sul tuo sito prima che lo facciano gli utenti.

Contatta il team di Chrome DevTools

Utilizza le seguenti opzioni per discutere di nuove funzionalità, aggiornamenti o qualsiasi altro argomento relativo a DevTools.