Migracja Puppeteer do TypeScript

Jack Franklin
Jacek Franklin

Jesteśmy wielbicielami TypeScriptu w zespole DevTools – tak bardzo, że w tych narzędziach powstają w nim nowy kod i jesteśmy w trakcie dużej migracji całej bazy kodu do sprawdzania jej typu przez TypeScript. Więcej informacji o tej migracji znajdziesz w naszej rozmowie z Chrome Dev Summit 2020. Warto więc rozważyć także migrację bazy kodu Puppeteer do TypeScript.

Planowanie migracji

Planując migrację, chcieliśmy postępować w małych krokach. Zmniejsza to nakład pracy podczas migracji – w każdej chwili możesz pracować tylko nad niewielkim fragmentem kodu, a jednocześnie zmniejsza ryzyko. Jeśli podczas któregoś z kroków coś pójdzie nie tak, możesz to łatwo cofnąć. Puppeteer ma wielu użytkowników, a uszkodzona wersja może spowodować problemy wielu z nich, dlatego tak ważne było, aby ograniczyć ryzyko wprowadzania zmian do minimum.

Mieliśmy też szczęście, że narzędzie Puppeteer udostępnia niezawodne testy jednostkowe obejmujące wszystkie funkcje aplikacji. Dzięki temu mieliśmy pewność, że nie doszło do łamania kodu podczas migracji, ale jednocześnie zyskaliśmy pewność, że nie wprowadzamy zmian w interfejsie API. Celem migracji było jej ukończenie, tak aby żaden użytkownik Puppeteer nawet nie wiedział, że przeprowadziliśmy migrację, a testy były istotną częścią tej strategii. Jeśli nie mieliśmy odpowiedniego zasięgu testów, warto by było je dodać przed kontynuacją migracji.

Wprowadzanie zmian w kodzie bez testów jest ryzykowne, ale zwłaszcza zmiany polegające na dotykaniu całych plików lub całej bazy kodu są ryzykowne. Przy wprowadzaniu zmian mechanicznych można łatwo przeoczyć jakiś krok, a testy wielokrotnie wykryły problem, który prześlizgł się zarówno przez osobę wdrażającą, jak i weryfikatora.

Na wstępie zajęliśmy się konfiguracją trybu ciągłej integracji (CI). Zauważyliśmy, że uruchomienia CI w odniesieniu do żądań pull były niestabilne i często kończyły się niepowodzeniem. Zdarzało się tak często, że przyzwyczailiśmy się do ignorowania naszego CI i mimo to scalania żądań pull, zakładając, że niepowodzenie dotyczyło pojedynczego problemu w CI, a nie problemu w Puppeteer.

Po ogólnej konserwacji i poświęcenie czasu na naprawienie niektórych regularnych problemów testowych udało nam się osiągnąć znacznie bardziej spójny stan, co umożliwiło nam wsłuchanie się w komunikaty CI i ustalenie, że awaria wskazuje na rzeczywisty problem. Ta praca nie jest świetna, a obserwacja niekończących się uruchomień CI jest frustrująca, ale ważne było, aby nasz pakiet testów działał niezawodnie, biorąc pod uwagę liczbę żądań pull, które wysyła migracja.

Wybierz i umieść 1 plik

Mieliśmy już gotowość do migracji i niezawodny serwer CI pełen testów, które analizowały nasze bezpieczeństwo. Zamiast zagłębiać się w dowolny plik, celowo wybraliśmy mały plik do migracji. To przydatne ćwiczenie, ponieważ pozwala sprawdzić planowany proces, który chcesz wykonać. Jeśli działa z tym plikiem, to podejście jest prawidłowe. Jeśli nie, możesz wrócić do deski rysunkowej.

Poza tym przesyłanie pliku po pliku (i w przypadku standardowych wersji Puppeteer, więc wszystkie zmiany nie były wysyłane w tej samej wersji npm) ograniczają ryzyko. Wybraliśmy DeviceDescriptors.js jako pierwszy plik, ponieważ był to jeden z najprostszych plików w bazie kodu. Wprowadzanie takiej drobnej zmiany może być nieco niepokojące, ale celem nie jest natychmiastowe wprowadzenie dużych zmian, lecz zachowanie ostrożności i systematyczne przesyłanie kolejnych plików. Czas poświęcony na weryfikację danego podejścia zdecydowanie oszczędza czas na późniejszym etapie migracji, gdy korzystasz z bardziej skomplikowanych plików.

Udowodnij wzór i powtórz

Na szczęście zmiana w DeviceDescriptors.js została wprowadzona w bazie kodu, a plan działa zgodnie z naszymi oczekiwaniami. Możesz teraz śmiało zająć się grą, a tak właśnie to zrobiliśmy. Etykieta GitHuba to świetny sposób na grupowanie wszystkich żądań pull. Okazało się, że przydaje się to do śledzenia postępów.

Przeprowadź migrację i popraw ją później

Nasz proces przebiegał tak:

  1. Zmień nazwę pliku z .js na .ts.
  2. Uruchom kompilator TypeScript.
  3. Rozwiąż ewentualne problemy.
  4. Utwórz żądanie pull.

Większość pracy w tych początkowych żądaniach pull polegała na wyodrębnieniu interfejsów TypeScriptu w przypadku istniejących struktur danych. W przypadku pierwszego żądania pull, które przeniosło plik DeviceDescriptors.js, o czym wcześniej wspomnieliśmy, kod pochodzi z:

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

I stał się:

interface Device {
  name: string,
  …
}

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

module.exports = devices;

W ramach tego procesu przeanalizowaliśmy każdy wiersz kodu, sprawdzając, czy nie występują problemy. Podobnie jak w przypadku każdej bazy kodu, która istnieje od kilku lat i z czasem się rozrasta, istnieją obszary, w których można refaktoryzować kod i poprawiać sytuację. Szczególnie po przejściu do TypeScriptu zauważyliśmy miejsca, w których drobna zmiana struktury kodu pozwoliłaby nam bardziej skupić się na kompilatorze i zapewnić większe bezpieczeństwo typów.

Wbrew pozorom ważne jest, aby od razu powstrzymać się od wprowadzania tych zmian. Celem migracji jest przeniesienie bazy kodu do TypeScriptu. Przez cały czas dużej migracji warto brać pod uwagę ryzyko awarii oprogramowania i użytkowników. Dzięki temu, że początkowe zmiany były nieznaczne, ograniczyliśmy to ryzyko. Po scaleniu pliku i migracji do TypeScriptu można było wprowadzić dalsze zmiany w celu ulepszenia kodu w celu wykorzystania systemu typów. Wyznacz ścisłe granice migracji i postaraj się ich trzymać.

Przeniesienie testów w celu przetestowania naszych definicji typów

Po przeniesieniu całego kodu źródłowego do TypeScriptu możemy zająć się testami. Nasze testy miały duży zasięg, ale wszystkie zostały napisane w języku JavaScript. Oznaczało to, że jedna z rzeczy, których nie sprawdzili, to nasze definicje typów. Jednym z długoterminowych celów projektu (nad którym nadal pracujemy) jest udostępnianie wysokiej jakości definicji typów od razu w Puppeteer. Nie mieliśmy jednak w bazie kodu żadnego sprawdzenia pod kątem tych definicji.

Dzięki migracji testów do TypeScriptu (według tych samych procesów, plik po pliku) znaleźliśmy problemy z naszymi skryptami TypeScript, które w innym przypadku pozostawałyby użytkownikom do znalezienia. Teraz nasze testy nie tylko obejmują wszystkie funkcje, ale również kontrolę jakości naszego języka TypeScript!

Już wcześniej osiągnęliśmy ogromne korzyści ze stosowania TypeScriptu, ponieważ pracują oni nad bazą kodu Puppeteer. W połączeniu ze znacznie ulepszonym środowiskiem CI pozwoliło nam to zwiększyć produktywność podczas pracy nad Puppeteer i wykryć błędy TypeScript, które w innym wypadku mogłyby zostać przekształcone w wersję npm. Cieszymy się, że wdrażamy wysokiej jakości definicje TypeScript, aby wszyscy deweloperzy używający platformy Puppeteer mogli korzystać z tych funkcji.

Pobieranie kanałów podglądu

Jako domyślnej przeglądarki programistycznej możesz użyć Chrome Canary, Dev lub Beta. Te kanały podglądu dają dostęp do najnowszych funkcji Narzędzi deweloperskich, testują nowoczesne interfejsy API platform internetowych oraz wykrywają problemy w witrynie, zanim zrobią to użytkownicy.

Kontakt z zespołem Narzędzi deweloperskich w Chrome

Użyj tych opcji, aby omówić nowe funkcje i zmiany w poście lub wszelkich innych sprawach związanych z Narzędziami dla programistów.

  • Sugestię lub opinię możesz przesłać na stronie crbug.com.
  • Aby zgłosić problem z Narzędziami deweloperskimi, kliknij Więcej opcji   Więcej   > Pomoc > Zgłoś problemy z Narzędziami deweloperskimi.
  • zatweetować na @ChromeDevTools.
  • Komentarze do filmów o narzędziach dla deweloperów w YouTube lub filmach w YouTube ze wskazówkami dotyczącymi Narzędzi deweloperskich.