Gostaria de compartilhar essa coisa interessante que recentemente aconteceu comigo enquanto desenvolvia um dos produtos de um de meus clientes.
Este cliente paga por um serviço que fornece uma API com dados extremamente relevantes para o produto, e há uma nova funcionalidade que acabou de ficar disponível: uma solução de embed configurável para exibir seus dados imediatamente no frontend, sem precisar escrever seu próprio frontend para exibir o conteúdo da integração da API.
Como essa funcionalidade poderia ser uma grande economia de tempo para os criadores de conteúdo na equipe do meu cliente, ela foi priorizada para funcionar no novo site deles (que é o produto que mencionei acima).
O problema: pontuação de desempenho do CWV
Já que o site depende de audiência para ganhar dinheiro, a otimização para motores de busca (SEO) não é negociável. E uma grande parte disso se tornou desempenho desde que o Google começou a usar métricas de Core Web Vitals (CWV) para ajudar a decidir quais páginas indexar primeiro.
Comecei implementando o embed da forma documentada: inserindo uma tag script na minha página. O problema é que a tag carregaria um arquivo de script muito grande que não era necessário na primeira carga da página, pois o embed só seria visto se o usuário descesse a página um pouco.
A solução prática: lazy load
Como o script não era necessário no primeiro carregamento da página e eu não tinha controle sobre ele de qualquer maneira, o seu carregamento poderia ser adiado, evitando requisições desnecessárias quando o usuário não chega a essa seção da página e também não afetando a pontuação de desempenho da CWV.
O frontend do site é feito em React, usando o framework Next. Eu não quero entrar em detalhes específicos sobre as decisões técnicas da minha equipe, mas essas duas são importantes para se ter em mente a fim de compreender como abordei esse problema. Com o Next, somos capazes de renderizar componentes React tanto no lado do servidor quanto no lado do cliente, então o que eu precisava implementar era um gatilho que só acionaria a renderização do componente inserindo o script do provedor quando o usuário tivesse rolado a página até onde ele estava posicionado.
Para isso, foi usado o react-cool-inview, mas entenda que há uma série de maneiras de alcançar resultados semelhantes e esse detalhe não é o ponto principal aqui, é apenas informativo.
Impacto: script do provedor não estava preparado para trabalhar corretamente com lazy loading
Quando eu pensei que meus problemas estariam resolvidos, houve uma grande surpresa: o embed não renderizava mais corretamente. Na verdade, achei que tinha desaparecido por um tempo, até que eu o encontrei abaixo de todos os elementos na página. Ao ler o script que foi baixado, e também uma grande advertência no console do navegador, a causa ficou clara: o script usava document.write() para renderizar seu conteúdo.
Você já deve saber o quanto é uma má prática usar document.write():
Do site da Mozilla Development Network:
“Aviso: o uso do método document.write() é fortemente desencorajado”.
Veja mais neste link.
Mas, prática ruim ou não, por que ele estava na parte inferior da página? Minha implementação padrão para carregar qualquer script neste site era usar o componente Script do Next, que faz o trabalho difícil de colocar corretamente o script de acordo com a estratégia de carregamento escolhida. E quando dizemos colocar corretamente uma tag de script, queremos dizer, ou no <head>, ou depois de todo o conteúdo antes da tag </body>, certo?
Não há nenhuma estratégia de carregamento para colocar o script inline exatamente onde eu adicionei seu código. Reparei que, como o document.write() estava sendo usado, o embed estava sendo renderizado exatamente onde o script estava posicionado.
A nova estratégia
Em seguida, o componente Script do Next foi substituído por uma tag de script HTML nativa renderizada no meio do conteúdo da página, como no exemplo fornecido. Mas como estava sendo carregado de forma lazy, o document.write() já não estava sendo chamado mais, e o seguinte erro estava aparecendo no console do navegador:
Falha ao executar “write” em “Document”: não é possível escrever em um documento a partir de um script externo carregado de forma assíncrona, a menos que seja explicitamente aberto.
Na verdade, eu ainda não entendo como funcionou quando eu estava usando o componente Script (mesmo ele estando no final da página). Talvez ele force document.open() e document.close() por debaixo dos panos.
A solução final
De qualquer forma, ainda não conseguia ver um exemplo que funcionasse na área reservada sem afetar o desempenho da primeira carga. A situação estava me incomodando bastante neste ponto. Por que eles criariam um script incorporado que não pode ser carregado seguindo as melhores práticas da web? E também por que uma solução tão ultrapassada como document.write() está sendo usada? E por que gastar meu tempo e dinheiro do meu cliente em uma solução que foi vendida como plug and play?
Então me ocorreu que, se eu conseguisse superar toda a frustração, talvez pudesse contar tudo isso a eles de uma maneira que alavancasse mudanças.
A mudança
Após trocar algumas mensagens no ticket de suporte, eu contei ao time de suporte sobre o problema com document.write() e estava difícil implementar o embed. Também enviei a documentação da MDN sobre o assunto. E eles concordaram em mudar seu código para parar de usá-lo!
Diria que ainda não é ideal, pois ainda precisamos imprimir a tag script exatamente onde o embed precisa ser renderizado e ignorar a solução padrão do Next para carregar scripts. Mas funcionou! E todos os embeds que precisamos podem ser carregados com lazy loading, então “não ideal” está funcionando muito bem por enquanto.
Confira mais conteúdos aqui no blog da Taller em #front-end