Desempenho de front-end 2021: definindo o ambiente

Publicados: 2022-03-10
Resumo rápido ↬ Vamos fazer 2021… rápido! Uma lista de verificação anual de desempenho de front-end com tudo o que você precisa saber para criar experiências rápidas na Web hoje, de métricas a ferramentas e técnicas de front-end. Atualizado desde 2016.

Índice

  1. Preparação: planejamento e métricas
  2. Definir metas realistas
  3. Definindo o Ambiente
  4. Otimizações de recursos
  5. Otimizações de compilação
  6. Otimizações de entrega
  7. Rede, HTTP/2, HTTP/3
  8. Teste e monitoramento
  9. Vitórias rápidas
  10. Tudo em uma página
  11. Baixe a lista de verificação (PDF, Apple Pages, MS Word)
  12. Assine nossa newsletter por e-mail para não perder os próximos guias.

Definindo o Ambiente

  1. Escolha e configure suas ferramentas de construção.
    Não dê muita atenção ao que é supostamente legal hoje em dia. Atenha-se ao seu ambiente de construção, seja Grunt, Gulp, Webpack, Parcel ou uma combinação de ferramentas. Contanto que você esteja obtendo os resultados de que precisa e não tenha problemas para manter seu processo de compilação, você está indo muito bem.

    Entre as ferramentas de compilação, o Rollup continua ganhando força, assim como o Snowpack, mas o Webpack parece ser o mais estabelecido, com literalmente centenas de plugins disponíveis para otimizar o tamanho de suas compilações. Fique atento ao Roteiro do Webpack 2021.

    Uma das estratégias mais notáveis ​​​​que apareceram recentemente é o agrupamento granular com Webpack no Next.js e no Gatsby para minimizar o código duplicado. Por padrão, os módulos que não são compartilhados em todos os pontos de entrada podem ser solicitados para rotas que não o utilizam. Isso acaba se tornando uma sobrecarga à medida que mais código é baixado do que o necessário. Com a fragmentação granular no Next.js, podemos usar um arquivo de manifesto de compilação do lado do servidor para determinar quais fragmentos de saída são usados ​​por diferentes pontos de entrada.

    Para reduzir o código duplicado em projetos Webpack, podemos usar fragmentação granular, habilitada em Next.js e Gatsby por padrão
    Para reduzir o código duplicado em projetos Webpack, podemos usar fragmentação granular, habilitada em Next.js e Gatsby por padrão. Crédito da imagem: Addy Osmani. (Visualização grande)

    Com SplitChunksPlugin, vários blocos divididos são criados dependendo de várias condições para evitar a busca de código duplicado em várias rotas. Isso melhora o tempo de carregamento da página e o armazenamento em cache durante as navegações. Enviado no Next.js 9.2 e no Gatsby v2.20.7.

    No entanto, começar com o Webpack pode ser difícil. Então, se você quiser mergulhar no Webpack, existem alguns ótimos recursos por aí:

    • A documentação do Webpack — obviamente — é um bom ponto de partida, assim como o Webpack — The Confusing Bits de Raja Rao e An Annotated Webpack Config de Andrew Welch.
    • Sean Larkin tem um curso gratuito sobre Webpack: The Core Concepts e Jeffrey Way lançou um curso gratuito fantástico sobre Webpack para todos. Ambos são ótimas introduções para mergulhar no Webpack.
    • Webpack Fundamentals é um curso de 4h muito abrangente com Sean Larkin, lançado pela FrontendMasters.
    • Exemplos de Webpack tem centenas de configurações de Webpack prontas para uso, categorizadas por tópico e finalidade. Bônus: há também um configurador de configuração do Webpack que gera um arquivo de configuração básica.
    • awesome-webpack é uma lista com curadoria de recursos, bibliotecas e ferramentas úteis do Webpack, incluindo artigos, vídeos, cursos, livros e exemplos para projetos Angular, React e framework-agnósticos.
    • A jornada para a rápida criação de ativos de produção com o Webpack é o estudo de caso da Etsy sobre como a equipe passou de um sistema de compilação JavaScript baseado em RequireJS para o uso do Webpack e como eles otimizaram suas compilações, gerenciando mais de 13.200 ativos em 4 minutos em média.
    • Dicas de desempenho do Webpack é um tópico de mina de ouro de Ivan Akulov, apresentando muitas dicas focadas em desempenho, incluindo aquelas focadas especificamente no Webpack.
    • awesome-webpack-perf é um repositório GitHub de mina de ouro com ferramentas e plugins úteis do Webpack para desempenho. Também mantido por Ivan Akulov.
Uma visualização da jornada do Etsy para construções rápidas de produção com o Webpack
A jornada do Etsy para uma produção rápida com Webpack (via Addy Osmani) (visualização grande)
  1. Use o aprimoramento progressivo como padrão.
    Ainda assim, depois de todos esses anos, manter o aprimoramento progressivo como princípio orientador de sua arquitetura e implantação de front-end é uma aposta segura. Projete e construa a experiência principal primeiro e, em seguida, aprimore a experiência com recursos avançados para navegadores capazes, criando experiências resilientes. Se o seu site for executado rápido em uma máquina lenta com uma tela ruim em um navegador ruim em uma rede abaixo do ideal, ele só será executado mais rápido em uma máquina rápida com um bom navegador em uma rede decente.

    Na verdade, com o serviço de módulo adaptável, parece que estamos levando o aprimoramento progressivo a outro nível, oferecendo experiências básicas "leves" para dispositivos de baixo custo e aprimorando com recursos mais sofisticados para dispositivos de ponta. O aprimoramento progressivo provavelmente não desaparecerá tão cedo.

  2. Escolha uma linha de base de desempenho forte.
    Com tantas incógnitas afetando o carregamento - a rede, limitação térmica, remoção de cache, scripts de terceiros, padrões de bloqueio de analisador, E/S de disco, latência de IPC, extensões instaladas, software antivírus e firewalls, tarefas de CPU em segundo plano, restrições de hardware e memória, diferenças no cache L2/L3, RTTS — JavaScript tem o custo mais alto da experiência, ao lado de fontes da Web que bloqueiam a renderização por padrão e imagens geralmente consumindo muita memória. Com os gargalos de desempenho se afastando do servidor para o cliente, como desenvolvedores, temos que considerar todas essas incógnitas com muito mais detalhes.

    Com um orçamento de 170 KB que já contém o caminho crítico HTML/CSS/JavaScript, roteador, gerenciamento de estado, utilitários, estrutura e a lógica do aplicativo, temos que examinar minuciosamente o custo de transferência de rede, o tempo de análise/compilação e o custo de tempo de execução do quadro de nossa escolha. Felizmente, vimos uma grande melhoria nos últimos anos na rapidez com que os navegadores podem analisar e compilar scripts. No entanto, a execução do JavaScript ainda é o principal gargalo, portanto, prestar muita atenção ao tempo de execução do script e à rede pode ser impactante.

    Tim Kadlec conduziu uma pesquisa fantástica sobre o desempenho de frameworks modernos e os resumiu no artigo "Os frameworks JavaScript têm um custo". Costumamos falar sobre o impacto de estruturas independentes, mas, como observa Tim, na prática, não é incomum ter várias estruturas em uso . Talvez uma versão mais antiga do jQuery que está sendo migrada lentamente para uma estrutura moderna, juntamente com alguns aplicativos legados usando uma versão mais antiga do Angular. Portanto, é mais razoável explorar o custo cumulativo de bytes JavaScript e o tempo de execução da CPU que podem facilmente tornar as experiências do usuário quase inúteis, mesmo em dispositivos de última geração.

    Em geral, as estruturas modernas não priorizam dispositivos menos poderosos , portanto, as experiências em um telefone e em um desktop geralmente serão drasticamente diferentes em termos de desempenho. De acordo com a pesquisa, sites com React ou Angular gastam mais tempo na CPU do que outros (o que obviamente não quer dizer que React é mais caro na CPU do que Vue.js).

    De acordo com Tim, uma coisa é óbvia: "se você estiver usando uma estrutura para construir seu site, estará fazendo uma troca em termos de desempenho inicial - mesmo nos melhores cenários".

O custo dos frameworks, tempo de CPU JavaScript: os sites SPA têm um desempenho ruim
O custo dos frameworks, adeus JavaScript: os sites SPA (ainda) têm um desempenho ruim
Tempo de CPU relacionado a scripts para dispositivos móveis e bytes JavaScript para dispositivos desktopv. Em geral, sites com React ou Angular gastam mais tempo na CPU do que outros. Mas isso depende de como você constrói o site. Pesquisa de Tim Kadlec. (Visualização grande)
  1. Avalie estruturas e dependências.
    Agora, nem todo projeto precisa de uma estrutura e nem toda página de um aplicativo de página única precisa carregar uma estrutura. No caso da Netflix, "remover o React, várias bibliotecas e o código de aplicativo correspondente do lado do cliente reduziu a quantidade total de JavaScript em mais de 200 KB, causando uma redução de mais de 50% no tempo de interatividade da Netflix para a página inicial desconectada ." A equipe então utilizou o tempo gasto pelos usuários na página de destino para pré-buscar o React para as páginas subsequentes que os usuários provavelmente acessariam (leia para obter detalhes).

    E daí se você remover completamente uma estrutura existente em páginas críticas? Com o Gatsby, você pode verificar o gatsby-plugin-no-javascript que remove todos os arquivos JavaScript criados pelo Gatsby dos arquivos HTML estáticos. No Vercel, você também pode permitir desabilitar o JavaScript em tempo de execução em produção para determinadas páginas (experimental).

    Depois que uma estrutura for escolhida, permaneceremos com ela por pelo menos alguns anos, portanto, se precisarmos usar uma, precisamos garantir que nossa escolha seja informada e bem considerada - e isso vale especialmente para as principais métricas de desempenho que se importar.

    Os dados mostram que, por padrão, os frameworks são bastante caros: 58,6% das páginas React enviam mais de 1 MB de JavaScript e 36% dos carregamentos de página Vue.js têm uma primeira pintura de conteúdo de <1,5s. De acordo com um estudo da Ankur Sethi, "seu aplicativo React nunca carregará mais rápido do que cerca de 1,1 segundo em um telefone médio na Índia, não importa o quanto você o otimize. Seu aplicativo Angular sempre levará pelo menos 2,7 segundos para inicializar. O os usuários do seu aplicativo Vue precisarão esperar pelo menos 1 segundo antes de poderem começar a usá-lo." Você pode não estar segmentando a Índia como seu mercado principal, mas os usuários que acessam seu site com condições de rede abaixo do ideal terão uma experiência comparável.

    É claro que é possível fazer SPAs rápidos, mas eles não são rápidos de fábrica, então precisamos levar em conta o tempo e o esforço necessários para fazê -los e mantê -los rápidos. Provavelmente será mais fácil escolher um custo de desempenho de linha de base leve desde o início.

    Então, como escolhemos uma estrutura ? É uma boa ideia considerar pelo menos o custo total em tamanho + tempos de execução iniciais antes de escolher uma opção; opções leves como Preact, Inferno, Vue, Svelte, Alpine ou Polymer podem fazer o trabalho muito bem. O tamanho de sua linha de base definirá as restrições para o código do seu aplicativo.

    Conforme observado por Seb Markbage, uma boa maneira de medir os custos iniciais de estruturas é primeiro renderizar uma visualização, excluí-la e renderizar novamente , pois isso pode informar como a estrutura é dimensionada. A primeira renderização tende a aquecer um monte de código compilado preguiçosamente, do qual uma árvore maior pode se beneficiar quando for dimensionada. A segunda renderização é basicamente uma emulação de como a reutilização de código em uma página afeta as características de desempenho à medida que a página cresce em complexidade.

    Você pode avaliar seus candidatos (ou qualquer biblioteca JavaScript em geral) no sistema de pontuação de escala de 12 pontos da Sacha Greif explorando recursos, acessibilidade, estabilidade, desempenho, ecossistema de pacotes , comunidade, curva de aprendizado, documentação, ferramentas, histórico , equipe, compatibilidade, segurança por exemplo.

    Perf Track rastreia o desempenho da estrutura em escala
    Perf Track rastreia o desempenho da estrutura em escala. (Visualização grande)

    Você também pode confiar nos dados coletados na web por um longo período de tempo. Por exemplo, o Perf Track rastreia o desempenho da estrutura em escala, mostrando pontuações de Core Web Vitals agregadas de origem para sites criados em Angular, React, Vue, Polymer, Preact, Ember, Svelte e AMP. Você pode até especificar e comparar sites criados com Gatsby, Next.js ou Create React App, bem como sites criados com Nuxt.js (Vue) ou Sapper (Svelte).

    Um bom ponto de partida é escolher uma boa pilha padrão para seu aplicativo. Gatsby (React), Next.js (React), Vuepress (Vue), Preact CLI e PWA Starter Kit fornecem padrões razoáveis ​​para carregamento rápido pronto para uso em hardware móvel médio. Além disso, dê uma olhada na orientação de desempenho específica do framework web.dev para React e Angular ( obrigado, Phillip! ).

    E talvez você possa adotar uma abordagem um pouco mais atualizada para criar aplicativos de página única – Turbolinks, uma biblioteca JavaScript de 15 KB que usa HTML em vez de JSON para renderizar visualizações. Portanto, quando você segue um link, o Turbolinks busca automaticamente a página, troca seu <body> e mescla seu <head> , tudo sem incorrer no custo de um carregamento completo da página. Você pode verificar detalhes rápidos e documentação completa sobre a pilha (Hotwire).

Um gráfico semelhante a um histograma mostrando o desempenho de computação dos telefones mais vendidos
Desempenho de CPU e computação dos telefones mais vendidos (Crédito da imagem: Addy Osmani) (visualização grande)
  1. Renderização do lado do cliente ou renderização do lado do servidor? Ambos!
    Essa é uma conversa bastante acalorada para se ter. A abordagem final seria configurar algum tipo de inicialização progressiva: use a renderização do lado do servidor para obter uma primeira exibição de conteúdo rápida, mas também inclua algum JavaScript mínimo necessário para manter o tempo de interação próximo ao da primeira exibição de conteúdo. Se o JavaScript chegar muito tarde após o FCP, o navegador bloqueará o thread principal ao analisar, compilar e executar o JavaScript descoberto tardiamente, prejudicando a interatividade do site ou aplicativo.

    Para evitá-lo, sempre divida a execução de funções em tarefas assíncronas separadas e, sempre que possível, use requestIdleCallback . Considere o carregamento lento de partes da interface do usuário usando o suporte dynamic import() do WebPack, evitando o custo de carregamento, análise e compilação até que os usuários realmente precisem deles ( obrigado Addy! ).

    Como mencionado acima, o Time to Interactive (TTI) nos informa o tempo entre a navegação e a interatividade. Em detalhes, a métrica é definida observando a primeira janela de cinco segundos após a renderização do conteúdo inicial, na qual nenhuma tarefa JavaScript leva mais de 50 ms ( Long Tasks ). Se ocorrer uma tarefa com mais de 50ms, a busca por uma janela de cinco segundos recomeça. Como resultado, o navegador primeiro assumirá que atingiu Interactive , apenas para mudar para Frozen , apenas para eventualmente voltar para Interactive .

    Assim que chegarmos ao Interactive , podemos - sob demanda ou conforme o tempo permitir - inicializar partes não essenciais do aplicativo. Infelizmente, como Paul Lewis notou, os frameworks normalmente não têm um conceito simples de prioridade que possa ser apresentado aos desenvolvedores e, portanto, a inicialização progressiva não é fácil de implementar com a maioria das bibliotecas e frameworks.

    Ainda assim, estamos chegando lá. Atualmente, existem algumas opções que podemos explorar, e Houssein Djirdeh e Jason Miller fornecem uma excelente visão geral dessas opções em sua palestra sobre Rendering on the Web e no artigo de Jason e Addy sobre Modern Front-End Architectures. A visão geral abaixo é baseada em seu trabalho estelar.

    • Renderização completa do lado do servidor (SSR)
      No SSR clássico, como o WordPress, todas as solicitações são tratadas inteiramente no servidor. O conteúdo solicitado é retornado como uma página HTML finalizada e os navegadores podem renderizá-lo imediatamente. Portanto, os aplicativos SSR não podem realmente usar as APIs DOM, por exemplo. A diferença entre a primeira pintura de conteúdo e o tempo de interação geralmente é pequena, e a página pode ser renderizada imediatamente à medida que o HTML está sendo transmitido para o navegador.

      Isso evita viagens de ida e volta adicionais para busca e modelagem de dados no cliente, pois isso é tratado antes que o navegador obtenha uma resposta. No entanto, acabamos com um tempo de raciocínio do servidor mais longo e, consequentemente, com o tempo até o primeiro byte e não usamos recursos responsivos e ricos de aplicativos modernos.

    • Renderização estática
      Construímos o produto como um aplicativo de página única, mas todas as páginas são pré-renderizadas para HTML estático com JavaScript mínimo como uma etapa de construção. Isso significa que, com renderização estática, produzimos arquivos HTML individuais para cada URL possível com antecedência, algo que poucos aplicativos podem pagar. Mas como o HTML de uma página não precisa ser gerado instantaneamente, podemos obter um tempo até o primeiro byte consistentemente rápido. Assim, podemos exibir uma página de destino rapidamente e, em seguida, pré-buscar uma estrutura SPA para as páginas subsequentes. A Netflix adotou essa abordagem, reduzindo o carregamento e o tempo para interação em 50%.

    • Renderização do lado do servidor com (Re)hidratação (Renderização universal, SSR + CSR)
      Podemos tentar usar o melhor dos dois mundos – as abordagens SSR e CSR. Com hidratação na mistura, a página HTML retornada do servidor também contém um script que carrega um aplicativo completo do lado do cliente. Idealmente, que obtenha uma primeira pintura de conteúdo rápida (como SSR) e continue a renderização com (re)hidratação. Infelizmente, isso raramente acontece. Mais frequentemente, a página parece pronta, mas não pode responder à entrada do usuário, produzindo cliques de raiva e abandonos.

      Com o React, podemos usar o módulo ReactDOMServer em um servidor Node como o Express, e então chamar o método renderToString para renderizar os componentes de nível superior como uma string HTML estática.

      Com o Vue.js, podemos usar o vue-server-renderer para renderizar uma instância do Vue em HTML usando renderToString . Em Angular, podemos usar @nguniversal para transformar solicitações de clientes em páginas HTML totalmente renderizadas pelo servidor. Uma experiência totalmente renderizada pelo servidor também pode ser obtida imediatamente com Next.js (React) ou Nuxt.js (Vue).

      A abordagem tem suas desvantagens. Como resultado, ganhamos total flexibilidade de aplicativos do lado do cliente ao mesmo tempo em que fornecemos renderização mais rápida do lado do servidor, mas também acabamos com uma lacuna maior entre a primeira pintura de conteúdo e o tempo de interação e um atraso maior na primeira entrada. A reidratação é muito cara e, geralmente, essa estratégia sozinha não será boa o suficiente, pois atrasa muito o Time To Interactive.

    • Streaming de renderização do lado do servidor com hidratação progressiva (SSR + CSR)
      Para minimizar a lacuna entre o tempo de interação e a primeira pintura de conteúdo, renderizamos várias solicitações de uma só vez e enviamos o conteúdo em partes à medida que são gerados. Portanto, não precisamos esperar pela sequência completa de HTML antes de enviar o conteúdo para o navegador e, portanto, melhorar o tempo até o primeiro byte.

      Em React, em vez de renderToString() , podemos usar renderToNodeStream() para canalizar a resposta e enviar o HTML em partes. No Vue, podemos usar renderToStream() que pode ser canalizado e transmitido. Com o React Suspense, podemos usar renderização assíncrona para esse propósito também.

      No lado do cliente, em vez de inicializar todo o aplicativo de uma vez, inicializamos os componentes progressivamente . As seções dos aplicativos são primeiro divididas em scripts autônomos com divisão de código e, em seguida, hidratadas gradualmente (na ordem de nossas prioridades). Na verdade, podemos hidratar os componentes críticos primeiro, enquanto o resto pode ser hidratado mais tarde. A função de renderização do lado do cliente e do lado do servidor pode ser definida de forma diferente por componente. Também podemos adiar a hidratação de alguns componentes até que eles apareçam ou sejam necessários para a interação do usuário ou quando o navegador estiver ocioso.

      Para o Vue, Markus Oberlehner publicou um guia sobre como reduzir o tempo de interação de aplicativos SSR usando hidratação na interação do usuário, bem como vue-lazy-hydration, um plug-in em estágio inicial que permite a hidratação do componente na visibilidade ou interação específica do usuário. A equipe Angular trabalha na hidratação progressiva com Ivy Universal. Você também pode implementar a hidratação parcial com Preact e Next.js.

    • Renderização Trisomórfica
      Com os service workers em vigor, podemos usar a renderização do servidor de streaming para navegações iniciais/não JS e, em seguida, fazer com que o service worker assuma a renderização do HTML para navegações após a instalação. Nesse caso, o service worker pré-renderiza o conteúdo e habilita as navegações no estilo SPA para renderizar novas exibições na mesma sessão. Funciona bem quando você pode compartilhar o mesmo código de modelagem e roteamento entre o servidor, a página do cliente e o service worker.

    Uma ilustração mostrando como a renderização trisomórfica funciona em 3 lugares, como renderização DOM, pré-renderização de service worker e renderização do lado do servidor
    Renderização trisomórfica, com a mesma renderização de código em 3 lugares: no servidor, no DOM ou em um service worker. (Fonte da imagem: Google Developers) (Visualização grande)
    • CSR com pré-renderização
      A pré-renderização é semelhante à renderização do lado do servidor, mas em vez de renderizar páginas no servidor dinamicamente, renderizamos o aplicativo para HTML estático no momento da compilação. Embora as páginas estáticas sejam totalmente interativas sem muito JavaScript do lado do cliente, a pré- renderização funciona de maneira diferente . Basicamente, ele captura o estado inicial de um aplicativo do lado do cliente como HTML estático em tempo de compilação, enquanto com a pré-renderização o aplicativo deve ser inicializado no cliente para que as páginas sejam interativas.

      Com o Next.js, podemos usar a exportação de HTML estático pré-renderizando um aplicativo para HTML estático. No Gatsby, um gerador de site estático de código aberto que usa React, usa o método renderToStaticMarkup em vez do método renderToString durante as compilações, com o bloco JS principal sendo pré-carregado e as rotas futuras são pré-buscadas, sem atributos DOM que não são necessários para páginas estáticas simples.

      Para o Vue, podemos usar o Vuepress para atingir o mesmo objetivo. Você também pode usar o prerender-loader com o Webpack. O Navi também fornece renderização estática.

      O resultado é um melhor tempo até o primeiro byte e primeira pintura de conteúdo, e reduzimos a lacuna entre o tempo de interação e a primeira pintura de conteúdo. Não podemos usar a abordagem se espera-se que o conteúdo mude muito. Além disso, todos os URLs precisam ser conhecidos com antecedência para gerar todas as páginas. Portanto, alguns componentes podem ser renderizados usando pré-renderização, mas se precisarmos de algo dinâmico, teremos que confiar no aplicativo para buscar o conteúdo.

    • Renderização completa do lado do cliente (CSR)
      Toda a lógica, renderização e inicialização são feitas no cliente. O resultado geralmente é uma enorme lacuna entre o tempo para interação e a primeira pintura de conteúdo. Como resultado, os aplicativos geralmente parecem lentos , pois o aplicativo inteiro precisa ser inicializado no cliente para renderizar qualquer coisa.

      Como o JavaScript tem um custo de desempenho, à medida que a quantidade de JavaScript cresce com um aplicativo, a divisão agressiva de código e o adiamento do JavaScript serão absolutamente necessários para domar o impacto do JavaScript. Para esses casos, uma renderização do lado do servidor geralmente será uma abordagem melhor, caso não seja necessária muita interatividade. Se não for uma opção, considere usar o App Shell Model.

      Em geral, o SSR é mais rápido que o CSR. Ainda assim, é uma implementação bastante frequente para muitos aplicativos por aí.

    Então, do lado do cliente ou do lado do servidor? Em geral, é uma boa ideia limitar o uso de estruturas totalmente do lado do cliente a páginas que as exigem absolutamente. Para aplicativos avançados, também não é uma boa ideia confiar apenas na renderização do lado do servidor. Tanto a renderização do servidor quanto a renderização do cliente são um desastre se forem mal feitas.

    Se você está inclinado para CSR ou SSR, certifique-se de renderizar pixels importantes o mais rápido possível e minimizar a lacuna entre essa renderização e o tempo de interação. Considere a pré-renderização se suas páginas não mudarem muito e adie a inicialização dos frameworks se puder. Transmita HTML em partes com renderização do lado do servidor e implemente hidratação progressiva para renderização do lado do cliente — e hidrate-se na visibilidade, interação ou durante o tempo ocioso para obter o melhor dos dois mundos.

Uma tabela comparando opções para renderização do lado do cliente versus renderização do lado do servidor
O espectro de opções para renderização no lado do cliente versus no lado do servidor. Além disso, confira a palestra de Jason e Houssein no Google I/O sobre Performance Implications of Application Architecture. (Fonte da imagem: Jason Miller) (Visualização grande)
Um exemplo do site do AirBnB mostrando sem hidratação progressiva à esquerda e com hidratação progressiva à direita
O AirBnB vem experimentando hidratação progressiva; eles adiam componentes desnecessários, carregam na interação do usuário (scroll) ou durante o tempo ocioso e os testes mostram que isso pode melhorar o TTI. (Visualização grande)
  1. Quanto podemos servir estaticamente?
    Esteja você trabalhando em um aplicativo grande ou em um site pequeno, vale a pena considerar qual conteúdo pode ser servido estaticamente a partir de um CDN (ou seja, JAM Stack), em vez de ser gerado dinamicamente em tempo real. Mesmo se você tiver milhares de produtos e centenas de filtros com muitas opções de personalização, ainda poderá servir suas páginas de destino críticas estaticamente e desacoplar essas páginas da estrutura de sua escolha.

    Existem muitos geradores de sites estáticos e as páginas que eles geram geralmente são muito rápidas. Quanto mais conteúdo pudermos pré-construir antecipadamente em vez de gerar visualizações de página em um servidor ou cliente no momento da solicitação, melhor desempenho alcançaremos.

    Em Construindo Sites Estáticos Parcialmente Hidratados e Progressivamente Aprimorados, Markus Oberlehner mostra como construir sites com um gerador de sites estáticos e um SPA, enquanto obtém aprimoramento progressivo e um tamanho mínimo de pacote JavaScript. Markus usa Eleventy e Preact como suas ferramentas e mostra como configurar as ferramentas, adicionar hidratação parcial, hidratação preguiçosa, arquivo de entrada de cliente, configurar Babel para Preact e agrupar Preact com Rollup — do início ao fim.

    Com o JAMStack usado em grandes sites atualmente, uma nova consideração de desempenho apareceu: o tempo de construção . Na verdade, criar até milhares de páginas a cada nova implantação pode levar minutos, por isso é promissor ver compilações incrementais no Gatsby que melhoram os tempos de compilação em 60 vezes , com integração em soluções CMS populares como WordPress, Contentful, Drupal, Netlify CMS e outros.

    Um fluxograma mostrando o Usuário 1 no canto superior esquerdo e o Usuário 2 no canto inferior esquerdo mostrando o processo de regeneração de status incremental
    Regeneração estática incremental com Next.js. (Crédito da imagem: Prisma.io) (Visualização grande)

    Além disso, o Next.js anunciou a geração estática incremental e antecipada, que nos permite adicionar novas páginas estáticas em tempo de execução e atualizar as páginas existentes depois que elas já foram criadas, renderizando-as novamente em segundo plano à medida que o tráfego chega .

    Precisa de uma abordagem ainda mais leve? Em sua palestra sobre Eleventy, Alpine e Tailwind: rumo a um Jamstack leve, Nicola Gutay explica as diferenças entre CSR, SSR e tudo no meio, e mostra como usar uma abordagem mais leve - junto com um repositório do GitHub que mostra a abordagem na prática.

  2. Considere usar o padrão PRPL e a arquitetura do shell do aplicativo.
    Estruturas diferentes terão efeitos diferentes no desempenho e exigirão diferentes estratégias de otimização, portanto, você precisa entender claramente todos os detalhes da estrutura em que estará confiando. Ao criar um aplicativo da Web, observe o padrão PRPL e a arquitetura do shell do aplicativo. A ideia é bem direta: envie o código mínimo necessário para ser interativo para que a rota inicial seja renderizada rapidamente, depois use o service worker para recursos de armazenamento em cache e pré-cache e, em seguida, carregue lentamente as rotas de que você precisa, de forma assíncrona.
Padrão PRPL na arquitetura do shell do aplicativo
PRPL significa Pushing critical resource, Rendering initial route, Pre-caching restantes rotas e Lazy-loading restantes rotas sob demanda.
Arquitetura do shell do aplicativo
Um shell de aplicativo é o mínimo de HTML, CSS e JavaScript que alimenta uma interface de usuário.
  1. Você otimizou o desempenho de suas APIs?
    APIs são canais de comunicação para um aplicativo expor dados a aplicativos internos e de terceiros por meio de endpoints . Ao projetar e construir uma API, precisamos de um protocolo razoável para permitir a comunicação entre o servidor e as solicitações de terceiros. Representational State Transfer ( REST ) é uma escolha lógica e bem estabelecida: ela define um conjunto de restrições que os desenvolvedores seguem para tornar o conteúdo acessível de maneira eficiente, confiável e escalável. Os serviços da Web que estão em conformidade com as restrições REST são chamados de serviços da Web RESTful .

    Assim como acontece com as boas e velhas solicitações HTTP, quando os dados são recuperados de uma API, qualquer atraso na resposta do servidor será propagado para o usuário final, atrasando a renderização . Quando um recurso deseja recuperar alguns dados de uma API, ele precisará solicitar os dados do endpoint correspondente. Um componente que renderiza dados de vários recursos, como um artigo com comentários e fotos do autor em cada comentário, pode precisar de várias viagens de ida e volta ao servidor para buscar todos os dados antes que possam ser renderizados. Além disso, a quantidade de dados retornados por meio do REST geralmente é maior do que o necessário para renderizar esse componente.

    Se muitos recursos exigirem dados de uma API, a API poderá se tornar um gargalo de desempenho. O GraphQL fornece uma solução de alto desempenho para esses problemas. Por si só, o GraphQL é uma linguagem de consulta para sua API e um tempo de execução do lado do servidor para executar consultas usando um sistema de tipos que você define para seus dados. Ao contrário do REST, o GraphQL pode recuperar todos os dados em uma única solicitação e a resposta será exatamente o que é necessário, sem excesso ou falta de dados, como normalmente acontece com o REST.

    Além disso, como o GraphQL está usando o esquema (metadados que informam como os dados estão estruturados), ele já pode organizar os dados na estrutura preferida, então, por exemplo, com o GraphQL, poderíamos remover o código JavaScript usado para lidar com o gerenciamento de estados, produzindo um código de aplicativo mais limpo que é executado mais rapidamente no cliente.

    Se você quiser começar a usar o GraphQL ou encontrar problemas de desempenho, estes artigos podem ser bastante úteis:

    • A GraphQL Primer: Por que precisamos de um novo tipo de API por Eric Baer,
    • A GraphQL Primer: A evolução do design de API por Eric Baer,
    • Projetando um servidor GraphQL para desempenho ideal por Leonardo Losoviz,
    • Desempenho do GraphQL explicado por Wojciech Trocki.
Dois exemplos de interfaces móveis para mensagens ao usar Redux/REST (esquerda) e Apollo/GraphQL (direita)
Uma diferença entre REST e GraphQL, ilustrada por meio de uma conversa entre Redux + REST à esquerda, Apollo + GraphQL à direita. (Fonte da imagem: Hacker Noon) (Visualização grande)
  1. Você usará AMP ou Instant Articles?
    Dependendo das prioridades e da estratégia da sua organização, você pode considerar usar o AMP do Google ou os Instant Articles do Facebook ou o Apple News da Apple. Você pode obter um bom desempenho sem eles, mas o AMP fornece uma estrutura de desempenho sólida com uma rede de entrega de conteúdo gratuita (CDN), enquanto os Instant Articles aumentarão sua visibilidade e desempenho no Facebook.

    O benefício aparentemente óbvio dessas tecnologias para os usuários é o desempenho garantido , portanto, às vezes, eles podem até preferir links AMP/Apple News/Instant Pages a páginas "regulares" e potencialmente inchadas. Para sites com conteúdo pesado que lidam com muito conteúdo de terceiros, essas opções podem ajudar a acelerar drasticamente os tempos de renderização.

    A menos que não. De acordo com Tim Kadlec, por exemplo, "documentos AMP tendem a ser mais rápidos do que seus equivalentes, mas não significam necessariamente que uma página tem desempenho. AMP não é o que faz a maior diferença do ponto de vista do desempenho".

    Um benefício para o proprietário do site é óbvio: descoberta desses formatos em suas respectivas plataformas e maior visibilidade nos mecanismos de pesquisa.

    Bem, pelo menos era assim que costumava ser. Como o AMP não é mais um requisito para o Top Stories , os editores podem estar migrando do AMP para uma pilha tradicional ( obrigado, Barry! ).

    Ainda assim, você também pode criar AMPs progressivos da Web, reutilizando AMPs como fonte de dados para seu PWA. Desvantagem? Obviamente, uma presença em um jardim murado coloca os desenvolvedores em posição de produzir e manter uma versão separada de seu conteúdo, e no caso de Instant Articles e Apple News sem URLs reais (obrigado Addy, Jeremy!) .

  2. Escolha sua CDN com sabedoria.
    Conforme mencionado acima, dependendo da quantidade de dados dinâmicos que você possui, você pode "terceirizar" parte do conteúdo para um gerador de site estático, enviando-o para um CDN e servindo uma versão estática dele, evitando assim solicitações ao servidor. Na verdade, alguns desses geradores são compiladores de sites com muitas otimizações automatizadas fornecidas prontas para uso. À medida que os compiladores adicionam otimizações ao longo do tempo, a saída compilada fica menor e mais rápida ao longo do tempo.

    Observe que as CDNs também podem servir (e descarregar) conteúdo dinâmico. Portanto, não é necessário restringir sua CDN a ativos estáticos. Verifique se o seu CDN realiza compactação e conversão (por exemplo, otimização de imagem e redimensionamento na borda), se eles fornecem suporte para trabalhadores de servidores, testes A/B, bem como inclusões de borda, que montam partes estáticas e dinâmicas de páginas na borda do CDN (ou seja, o servidor mais próximo do usuário) e outras tarefas. Além disso, verifique se o seu CDN suporta HTTP sobre QUIC (HTTP/3).

    Katie Hempenius escreveu um guia fantástico para CDNs que fornece informações sobre como escolher um bom CDN , como ajustá-lo e todas as pequenas coisas a serem lembradas ao avaliar um. Em geral, é uma boa ideia armazenar em cache o conteúdo da forma mais agressiva possível e habilitar recursos de desempenho de CDN como Brotli, TLS 1.3, HTTP/2 e HTTP/3.

    Nota : com base na pesquisa de Patrick Meenan e Andy Davies, a priorização HTTP/2 é efetivamente quebrada em muitas CDNs, portanto, tenha cuidado ao escolher uma CDN. Patrick tem mais detalhes em sua palestra sobre priorização HTTP/2 ( obrigado, Barry! ).

    Visualização CDNPerf de nomes CDN e velocidade de consulta em ms
    O CDNPerf mede a velocidade de consulta para CDNs reunindo e analisando 300 milhões de testes todos os dias. (Visualização grande)

    Ao escolher uma CDN, você pode usar esses sites de comparação com uma visão detalhada de seus recursos:

    • Comparação de CDN, uma matriz de comparação de CDN para Cloudfront, Aazure, KeyCDN, Fastly, Verizon, Stackpach, Akamai e muitos outros.
    • O CDN Perf mede a velocidade de consulta para CDNs reunindo e analisando 300 milhões de testes todos os dias, com todos os resultados baseados em dados RUM de usuários de todo o mundo. Verifique também a comparação de desempenho de DNS e a comparação de desempenho de nuvem.
    • O CDN Planet Guides fornece uma visão geral das CDNs para tópicos específicos, como Servir obsoleto, Purge, Origin Shield, Prefetch e Compression.
    • Web Almanac: CDN Adoption and Usage fornece informações sobre os principais provedores de CDN, seu gerenciamento de RTT e TLS, tempo de negociação de TLS, adoção de HTTP/2 e outros. (Infelizmente, os dados são apenas de 2019).

Índice

  1. Preparação: planejamento e métricas
  2. Definir metas realistas
  3. Definindo o Ambiente
  4. Otimizações de recursos
  5. Otimizações de compilação
  6. Otimizações de entrega
  7. Rede, HTTP/2, HTTP/3
  8. Teste e monitoramento
  9. Vitórias rápidas
  10. Tudo em uma página
  11. Baixe a lista de verificação (PDF, Apple Pages, MS Word)
  12. Assine nossa newsletter por e-mail para não perder os próximos guias.