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

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

ReportingObserver informa quando seu site usa uma API descontinuada ou é executado em uma intervenção do navegador. A funcionalidade básica foi lançada originalmente no Chrome 69. A partir do Chrome 84, ele pode ser usado 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álises para análise.

Por que isso é útil? Até essa API, os avisos de descontinuação e intervenção só estavam disponíveis 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 de rede. Assim, talvez você nem veja essas mensagens ao desenvolver/testar um site localmente. O ReportingObserver oferece uma solução para esse problema. Quando os usuários encontram possíveis problemas no mundo real, os desenvolvedores da Web podem ser notificados sobre eles.

Contexto

Há algum tempo, escrevi uma postagem no blog (Observar seu app da Web) porque achei fascinante a quantidade de APIs 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 as medições de performance. E métodos como window.onerror e window.onunhandledrejection até nos informam quando algo dá errado.

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

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

Naturalmente, você pode pensar que window.onerror captura esses avisos. Isso não é verdadeiro. Isso ocorre porque window.onerror não é acionado para avisos gerados diretamente pelo user agent. Ele é acionado para erros de execução (excpeções do JavaScript e erros de sintaxe) causados pela execução do código.

ReportingObserver aproveita a folga. Ele 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 geração de relatórios e não se preocupar tanto se os usuários estão enfrentando problemas inesperados no site.

A API

ReportingObserver não é diferente de outras APIs do Observer, como IntersectionObserver e ResizeObserver. Você fornece um callback, que fornece 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órios. No momento, há dois tipos de relatório: 'deprecation' e 'intervention'.

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

Relatórios armazenados 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 com atraso, mas você não perde nada do que aconteceu antes no carregamento da página.

Parar de observar

Interrompa a observação usando o método disconnect():

observer.disconnect();

Exemplos

Informar as 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();

Receba 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 mais uma maneira de descobrir e monitorar possíveis problemas no seu app da Web. Ele é até uma ferramenta útil para entender a integridade da base de código (ou a falta dela). Envie relatórios para um back-end, saiba sobre os problemas reais, atualize o código e ganhe dinheiro.

Trabalho futuro

No futuro, espero que ReportingObserver se torne a API de fato para detectar todos os tipos de problemas no JavaScript. Imagine uma API para detectar tudo que der errado no app:

Outros recursos:

Imagem principal de Sieuwert Otterloo no Unsplash.