Adicione atributos defer a todos os scripts, se possível. Adiar o carregamento e a execução de JavaScript permite que o navegador comece a analisar o HTML, renderizar e pintar.
Assim, algum conteúdo estático intermediário pode ser exibido bem no início (ou até mesmo antes) do processo de inicialização do Discourse. Isso deve ser suficiente para uma velocidade de carregamento de página percebida pelo usuário mais rápida na primeira carga da página.
Isso faria com que o LCP ainda ocorresse após o EmberJS inicializar e renderizar novamente, não abordando o problema principal em relação às novas classificações do Google.
Esse é o nosso plano atual de médio prazo para abordar o LCP no Discourse.
A partir do Chrome 88, isso felizmente não é mais verdade!
Também não sabia disso até agora. :))
“Antes desta alteração, um elemento que era removido fazia com que ele não fosse mais considerado um candidato válido para LCP. […] Após esta alteração, um elemento que é removido ainda é considerado um candidato válido para LCP.”
“A alteração para incluir conteúdo que é posteriormente removido do DOM como possíveis maiores pinturas de conteúdo melhorará os tempos de Largest Contentful Paint em sites que possuem imagens [para Discourse:elementos de texto] do mesmo tamanho inseridos várias vezes. Este é um padrão comum para carrosséis, bem como para alguns frameworks JavaScript que fazem renderização do lado do servidor.”
0s-2s - tela em branco:
O WebPageTest ignora defer para JavaScript e baixa todos os JavaScripts antes de fazer uma primeira pintura - isso funciona corretamente em um dispositivo real.
2.5s - LCP: conteúdo estático do renderização do lado do servidor
3.5s - Mudança Visual: logo carregado
6.5s - Mudança Visual: conteúdo do renderização do EmberJs
7s - Completo Visual
PageSpeed Insights
Elemento Largest Contentful Paint
O PageSpeed identifica corretamente o nó de texto estático da renderização do lado do servidor como o elemento FCP LCP: div.row > div.topic-body > div.post > p
Nó de texto renderizado pelo EmberJs: div.row > div.topic-body > div.regular.contents > div.cooked > p
Mas parece que o PageSpeed não usa o nó de texto estático corretamente identificado para seu resultado simulado: FCP e LCP simulados são muito grandes.
Observação sobre o First Input Delay: Esperei até a página carregar completamente e então cliquei no fundo - então, depois que a renderização do EmberJs terminou.
Observação sobre o First Input Delay: Aqui cliquei no fundo imediatamente quando o conteúdo estático ficou visível pela primeira vez. Adicione meu tempo de reação em cima deste FID.
Observação extra sobre percentis abaixo das barras nestes gráficos:
Os percentis não são tão relevantes, pois apenas comparam os valores medidos com os valores de origem. A origem é uma página web TYPO3 com uma instalação de Discourse em uma subpasta.
Concordo totalmente que o Discourse é um aplicativo web muito lento e pesado em JS. Se pudermos adiar os ARQUIVOS CSS/JS, isso ajudará enormemente a acelerar LCP, FCP, FID, CLS.
Seria muito útil ver isso sendo implementado. Nós e muitas outras pessoas estamos enfrentando esse problema. Todos os sites do Discourse estão falhando no Core Web Vitals. Se servirmos uma página HTML ESTÁTICA rápida aos usuários na primeira vez e/ou adiarmos toda a lógica JS/CSS na primeira carga inicial, dessa forma poderemos acelerar todas as páginas e passar nas pontuações do CWV! Animado para ver isso implementado em uma atualização principal do Discourse.
Todas as classificações do Google dos sites do Discourse estão caindo devido aos sites não passarem no Core Web Vitals.
Estamos abertos a experimentar isso no core. O ‘flash’ de conteúdo com estilos diferentes pode ser um pouco desconcertante, então gostaríamos de começar com ele desativado por padrão em uma configuração de site “experimental”. Dessa forma, os administradores do site podem optar por ativá-lo, se quiserem.
Você consegue tentar adicionar uma configuração de site em seu PR @rrit? Também seria bom adicionar alguns testes RSpec para verificar o comportamento com a configuração ativada / desativada.
Isso não significa que podemos simplesmente colocar um spinner em tela cheia (que tem 100% de largura e 100% de altura) na página renderizada pelo servidor e substituí-lo pelo aplicativo Ember quando ele finalmente inicializar para obter um LCP extremamente baixo?
Poderíamos fazer esse spinner ser um SVG que imita a interface do usuário do Discourse para que a transição seja mais suave e menos parecida com FOUC.
Eu tive que desabilitar o defer tag para o QUnit Test Runner: app/views/qunit/index.html.erb
Antes, os testes QUnit ainda rodavam com o feature flag "javascript defer" = false. E agora os testes rodam também com "javascript defer" = true.
Imagens de viewport completo, que são visualmente equivalentes a imagens de fundo, não são mais consideradas como a maior pintura de conteúdo (largest contentful paint)
Para elementos de texto, apenas o tamanho de seus nós de texto é considerado (o menor retângulo que abrange todos os nós de texto).
Para todos os elementos, qualquer margem, preenchimento ou borda aplicada via CSS não é considerada.
É por isso que o nó de texto estático deve ser renderizado exatamente do mesmo tamanho que o nó de texto EmberJs.
Ou até um pouco maior, aumentando a line-height.
Por exemplo, se a largura dos nós de texto não corresponder, há muitos casos geométricos introduzidos por diferentes quebras de linha onde o nó de texto estático se torna menor que o EmberJs.
Na verdade, usei a renderização noscript das postagens dentro de uma página de tópico. As classes CSS correspondem ligeiramente às reais - então a aparência é igual.
No POC existem duas funcionalidades combinadas - devemos dividi-las em duas flags de funcionalidade experimental?
JavaScript com tag defer (flag de funcionalidade no painel de configurações) (flag de funcionalidade oculta, pois uma reconstrução do container ou um flush do cache do tema é necessária para isso) ← Correção: alternância rápida com cache
Exibição de conteúdo estático na visualização do tópico (flag de funcionalidade no painel de configurações)
Claro, o impacto total no LCP é alcançado apenas usando ambos: FCP: conteúdo estático
Pode haver instâncias do Discourse onde plugins ou componentes de tema falham na deferência do JS. Ao dividir essas funcionalidades, elas podem ter um pequeno ganho no conteúdo estático sem adiar o JS: FCP: conteúdo estático sem adiar JS
Vamos esperar mais 7-14 dias para, esperançosamente, ver mais melhorias para páginas mobile, já que os valores são calculados com a média dos últimos 28 dias - contando apenas 12 dias com o POC aplicado no momento.
A Prova de Conceito (POC) está em vigor desde 30/01/2022 e levou mais de 4 semanas para afetar todas as páginas no relatório “Core Web Vitals” do Google Search Console - com base nos dados do CrUX.
Todas as páginas de tópicos estão na zona verde do LCP (medido pelo CrUX):
Desktop: LCP 1,7 seg
Mobile: LCP 2,0 seg
Dados do LCP: Google Search Console/CrUX
Impressão do Google Search Console com a POC aplicada desde 30/01/2022:
@rrit obrigado por compartilhar os dados do seu site! Discutimos isso internamente e, receio que não adicionaremos essa funcionalidade ao Discourse core no momento.
Embora as métricas do Web Vital que você compartilhou sejam muito impressionantes, o flash de conteúdo de ‘visualização de crawler’ não proporciona uma boa experiência ao usuário. As alterações de estilo que você fez certamente ajudam, mas precisarão ser ajustadas para cada site Discourse que tiver estilo personalizado.
Nosso objetivo de longo prazo é implementar o renderização do lado do servidor real usando algo como o Ember FastBoot. Teoricamente, isso forneceria as mesmas melhorias estatísticas que você mediu, ao mesmo tempo que proporcionaria uma experiência de usuário perfeita. Preferiríamos focar nossos esforços nesse objetivo.
Dito isso, o Discourse é super extensível, então acho que seria totalmente possível implementar sua ideia em um plugin Discourse e compartilhá-lo aqui em Plugin.
A maior alteração que você fez no PR principal é adicionar o atributo defer às tags de script. Substituir todos esses locais de um plugin seria muito difícil. No entanto, acho que o mesmo resultado poderia ser alcançado com uma abordagem baseada em middleware. Encontrei este post de blog que descreve um problema semelhante:
Usando essa técnica, você poderia escrever um middleware que verifica respostas text/html, as analisa e, em seguida, adiciona atributos defer onde necessário.
Adicionar middleware a partir de um plugin pode ser feito algo como isto:
# name: meu-plugin
# about: Descrição do meu plugin
# version: 1.0
# url: https://example.org
require_relative "lib/script_defer_middleware"
on(:after_initializers) do
Rails.configuration.middleware.use(ScriptDeferMiddleware)
end
Se você encontrar algum obstáculo com uma abordagem baseada em plugin, sinta-se à vontade para postar aqui e ficaremos felizes em tentar apontá-lo na direção certa.