Como migrar o Puppeteer para o TypeScript

Somos grandes fãs do TypeScript na equipe do DevTools. Tanto que o novo código no DevTools está sendo criado nele e estamos no meio de uma grande migração de toda a base de código para serem verificados pelo TypeScript. Saiba mais sobre essa migração na nossa palestra no Chrome Dev Summit 2020. Portanto, faz sentido migrar a base de código do Puppeteer para o TypeScript.

Como planejar a migração

Ao planejar a migração, queríamos fazer progressos em pequenas etapas. Isso reduz a sobrecarga da migração, já que você trabalha apenas em uma pequena parte do código por vez, além de reduzir o risco. Se algo der errado com uma das etapas, você pode revertê-lo facilmente. O Puppeteer tem muitos usuários, e uma versão com falhas causaria problemas para muitos deles. Por isso, era vital manter o risco de mudanças mínimas.

Também tivemos a sorte de ter um conjunto robusto de testes de unidade que abrange toda a funcionalidade do Puppeteer. Isso significa que podemos ter certeza de que não interrompemos o código durante a migração, mas também de que não introduzimos mudanças na API. A meta da migração era concluí-la sem que nenhum usuário do Puppeteer percebesse que havíamos migrado, e os testes foram uma parte vital dessa estratégia. Se não tivéssemos uma boa cobertura de teste, teríamos adicionado isso antes de continuar com a migração.

Realizar qualquer mudança de código sem testes é arriscado, mas as mudanças em que você está tocando arquivos inteiros ou em toda a base de código são especialmente arriscadas. Ao fazer alterações mecânicas, é fácil perder uma etapa e, em várias ocasiões, os testes detectaram um problema que passou tanto pelo implementador quanto pelo revisor.

Uma coisa que investimos tempo de antemão foi a configuração de integração contínua (CI). Percebemos que as execuções de CI em solicitações de pull eram instáveis e muitas vezes falhavam. Isso acontecia com tanta frequência que nos acostumamos a ignorar nossa CI e mesclar as solicitações de envio mesmo assim, supondo que a falha fosse um problema único na CI e não um problema no Puppeteer.

Depois de um tempo dedicado à manutenção geral e à correção de alguns erros de teste comuns, conseguimos um estado de aprovação muito mais consistente, o que nos permitiu ouvir a CI e saber que uma falha estava indicando um problema real. Esse trabalho não é glamouroso, e é frustrante assistir a execuções de CI sem fim, mas era vital ter nosso pacote de testes funcionando de forma confiável, considerando o número de solicitações de pull que a migração estava gerando.

Escolha e localize um arquivo

Nesse ponto, nossa migração estava pronta para ser iniciada e um servidor de CI robusto, cheio de testes, nos protegia. Em vez de mergulhar em qualquer arquivo arbitrário, escolhemos um arquivo pequeno para migrar. Esse é um exercício útil porque permite validar o processo planejado que você está prestes a realizar. Se funcionar nesse arquivo, sua abordagem será válida; caso contrário, você pode voltar para a prancheta.

Além disso, a verificação de arquivo por arquivo (e com versões regulares do Puppeteer, para que todas as mudanças não fossem enviadas na mesma versão do npm) reduziu o risco. Escolhemos DeviceDescriptors.js como o primeiro arquivo por ser um dos mais simples da base de código. Pode parecer um pouco decepcionante fazer todo esse trabalho de preparação e chegar a uma mudança tão pequena, mas o objetivo não é fazer grandes mudanças imediatamente, mas prosseguir com cautela e metodicamente arquivo por arquivo. O tempo gasto na validação da abordagem economiza tempo mais tarde na migração, quando você encontra arquivos mais complicados.

Prove o padrão e repita

Felizmente, a mudança para DeviceDescriptors.js foi feita na base de código, e o plano funcionou como esperávamos. Agora você está pronto para começar a trabalhar, e é exatamente o que fizemos. Usar um rótulo do GitHub é uma ótima maneira de agrupar todas as solicitações de envio. Isso foi útil para acompanhar o progresso.

Migrar e melhorar depois

Para qualquer arquivo JavaScript individual, nosso processo foi:

  1. Renomeie o arquivo de .js como .ts.
  2. Execute o compilador do TypeScript.
  3. Corrija os problemas.
  4. Crie a solicitação de envio.

A maior parte do trabalho nesses pull requests iniciais foi extrair interfaces do TypeScript para estruturas de dados existentes. No caso do primeiro pull request que migrou DeviceDescriptors.js, o código passou de:

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

E se tornou:

interface Device {
  name: string,
  
}

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

module.exports = devices;

Como parte desse processo, trabalhamos em cada linha da base de código verificando se há problemas. Como acontece com qualquer base de código criada há alguns anos e que cresceu ao longo do tempo, há áreas de oportunidade para refatorar o código e melhorar a situação. Especialmente com a mudança para o TypeScript, identificamos lugares em que uma pequena reestruturação do código nos permitiria depender mais do compilador e ter uma melhor segurança de tipo.

Contrariando a intuição, é muito importante não fazer essas mudanças imediatamente. O objetivo da migração é colocar a base de código no TypeScript. Durante uma migração grande, você precisa pensar o tempo todo sobre o risco de causar falhas no software e para os usuários. Ao manter as mudanças iniciais mínimas, reduzimos o risco. Depois que o arquivo foi mesclado e migrado para o TypeScript, foi possível fazer mudanças para melhorar o código e aproveitar o sistema de tipos. Defina limites rígidos para a migração e tente ficar dentro deles.

Como migrar os testes para testar nossas definições de tipo

Depois de migrar todo o código-fonte para o TypeScript, vamos focar nos testes. Nossos testes tiveram uma ótima cobertura, mas foram todos escritos em JavaScript. Isso significa que uma coisa que eles não testaram foram nossas definições de tipo. Um dos objetivos de longo prazo do projeto (ainda estamos trabalhando) é enviar definições de tipo prontas para uso com o Puppeteer, mas não tínhamos nenhuma verificação na nossa base de código sobre as definições de tipo.

Ao migrar os testes para o TypeScript (seguindo o mesmo processo, arquivo por arquivo), encontramos problemas com o TypeScript que, de outra forma, seriam deixados pelos usuários. Agora nossos testes não apenas abrangem todas as nossas funcionalidades, mas também funcionam como uma verificação de qualidade do TypeScript.

Já nos beneficiamos muito com o TypeScript como engenheiros que trabalham na base de código do Puppeteer. Aliado ao nosso ambiente de CI muito aprimorado, ele nos permitiu aumentar a produtividade ao trabalhar no Puppeteer e fazer com que o TypeScript capturasse bugs que, de outra forma, teriam sido lançados em uma versão de npm. Estamos felizes em receber as definições de alta qualidade do TypeScript enviadas para permitir que todos os desenvolvedores que usam o Puppeteer também se beneficiem desse trabalho.

Fazer o download dos canais de visualização

Considere usar o Chrome Canary, Dev ou Beta como seu navegador de desenvolvimento padrão. Esses canais de visualização dão acesso aos recursos mais recentes do DevTools, permitem testar APIs de plataforma da Web de última geração e ajudam a encontrar problemas no seu site antes que os usuários.

Entre em contato com a equipe do Chrome DevTools

Use as opções a seguir para discutir os novos recursos, atualizações ou qualquer outra coisa relacionada ao DevTools.