Conheça a integridade do seu código com a API ReportingObserver

Encontre APIs descontinuadas nos seus apps de produção.

O ReportingObserver informa quando seu site usa uma API descontinuada ou encontra uma intervenção do navegador. A funcionalidade básica foi lançada originalmente no Chrome 69. A partir do Chrome 84, ela pode ser usada em workers.

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    console.log(report.type, report.url, report.body);
  }
}, {buffered: true});

observer.observe();

Use o callback para enviar relatórios a um back-end ou provedor de análise para análise.

Por que isso é útil? Até essa API, os avisos de descontinuação e intervenção estavam disponíveis apenas no DevTools como mensagens do console. As intervenções, em particular, são acionadas apenas por várias restrições do mundo real, como condições de dispositivo e rede. Assim, talvez você nunca veja essas mensagens ao desenvolver/testar um site localmente. O ReportingObserver oferece uma solução para esse problema. Quando os usuários enfrentam possíveis problemas em campo, os desenvolvedores web podem ser notificados sobre eles.

Contexto

Há algum tempo, escrevi uma postagem no blog (Observing your web app) porque achei fascinante quantas APIs existem para monitorar as "coisas" que acontecem em um app da Web. Por exemplo, há APIs que podem observar informações sobre o DOM: ResizeObserver, IntersectionObserver, MutationObserver. PerformanceObserver captura medições de desempenho. E métodos como window.onerror e window.onunhandledrejection até nos avisam quando algo dá errado.

No entanto, existem outros tipos de avisos que não são capturados pelas APIs atuais. Quando seu site usa uma API descontinuada ou se depara com uma intervenção do navegador, o DevTools é o primeiro a informar sobre isso:

Avisos do console do DevTools para descontinuações e intervenções.
Avisos iniciados pelo navegador no console do DevTools.

É natural pensar que window.onerror captura esses avisos. Isso não é verdadeiro. Isso ocorre porque window.onerror não é acionado para avisos gerados diretamente pelo próprio user agent. Ele é acionado para erros de tempo de execução (exceções de JavaScript e erros de sintaxe) causados pela execução de código.

ReportingObserver assume o controle. Ela oferece uma maneira programática de receber notificações sobre avisos emitidos pelo navegador, como descontinuações e intervenções. Você pode usá-lo como uma ferramenta de relatórios e ficar mais tranquilo sabendo se os usuários estão enfrentando problemas inesperados no seu site ativo.

A API

A ReportingObserver é semelhante às outras APIs do Observer, como IntersectionObserver e ResizeObserver. Você fornece um callback, e ele retorna informações. As informações que o callback recebe são uma lista de problemas causados pela página:

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    // → report.type === 'deprecation'
    // → report.url === 'https://reporting-observer-api-demo.glitch.me'
    // → report.body.id === 'XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload'
    // → report.body.message === 'Synchronous XMLHttpRequest is deprecated...'
    // → report.body.lineNumber === 11
    // → report.body.columnNumber === 22
    // → report.body.sourceFile === 'https://reporting-observer-api-demo.glitch.me'
    // → report.body.anticipatedRemoval === <JS_DATE_STR> or null
  }
});

observer.observe();

Relatórios filtrados

Os relatórios podem ser pré-filtrados para observar apenas determinados tipos de relatório. No momento, há dois tipos de relatório: 'deprecation' e 'intervention'.

const observer = new ReportingObserver((reports, observer) => {
  …
}, {types: ['deprecation']});

Relatórios em buffer

Use a opção buffered: true quando quiser ver os relatórios que foram gerados antes da criação da instância do observador:

const observer = new ReportingObserver((reports, observer) => {
  …
}, {types: ['intervention'], buffered: true});

Essa opção é ótima para situações como o carregamento lento de uma biblioteca que usa um ReportingObserver. O observador é adicionado tarde, mas você não perde nada do que aconteceu antes no carregamento da página.

Parar de observar

Pare de observar usando o método disconnect():

observer.disconnect();

Exemplos

Informar intervenções do navegador a um provedor de análise

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    sendReportToAnalytics(JSON.stringify(report.body));
  }
}, {types: ['intervention'], buffered: true});

observer.observe();

Receber notificações quando as APIs forem removidas

const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    if (report.type === 'deprecation') {
      sendToBackend(`Using a deprecated API in ${report.body.sourceFile} which will be
                     removed on ${report.body.anticipatedRemoval}. Info: ${report.body.message}`);
    }
  }
});

observer.observe();

Conclusão

O ReportingObserver oferece uma maneira adicional de descobrir e monitorar possíveis problemas no seu app da Web. Ele é até mesmo uma ferramenta útil para entender a integridade da sua base de código (ou a falta dela). Envie relatórios para um back-end, conheça os problemas reais, atualize o código e aproveite!

Trabalho futuro

No futuro, espero que a ReportingObserver se torne a API padrão para detectar todos os tipos de problemas em JavaScript. Imagine uma API para capturar tudo o que dá errado no seu app:

Outros recursos:

Imagem principal de Sieuwert Otterloo no Unsplash.