Pré-carregar módulos

Sérgio Gomes

O desenvolvimento baseado em módulos oferece algumas vantagens reais em termos de capacidade de armazenamento em cache, o que ajuda a reduzir o número de bytes que você precisa enviar aos usuários. A granularidade mais fina do código também ajuda no carregamento da história, permitindo e priorizar o código crítico do seu aplicativo.

No entanto, as dependências de módulo introduzem um problema de carregamento, já que o navegador precisa aguardar o carregamento de um módulo para descobrir quais são as dependências. Só de ida para isso é pré-carregando as dependências, para que o navegador saiba de todos os arquivos com antecedência e pode manter a conexão ocupada.

<link rel="preload"> é uma forma de solicitar recursos declarativamente com antecedência, antes que o navegador precise delas.

<head>
  <link rel="preload" as="style" href="critical-styles.css">
  <link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>

Compatibilidade com navegadores

  • Chrome: 50.
  • Borda: ≤ 79.
  • Firefox: 85.
  • Safari: 11.1.

Origem

Isso funciona muito bem com recursos como fontes, que muitas vezes estão escondidas em arquivos CSS, às vezes com vários níveis de profundidade. Nesse caso, o navegador teria que esperar várias idas e voltas antes de descobrir que precisa buscar um arquivo de fonte grande, quando poderia ter usado esse tempo para iniciar o download e aproveitar toda a largura de banda da conexão.

O <link rel="preload"> e o cabeçalho HTTP equivalente oferecem uma API simples e maneira de informar imediatamente o navegador sobre os arquivos críticos que serão necessários como parte da navegação atual. Quando o navegador vê o pré-carregamento, ele inicia uma alta um download prioritário para o recurso, de modo que, quando for realmente necessário, buscados ou em parte lá. No entanto, ele não funciona para módulos.

É aqui que as coisas ficam complicadas. Há vários modos de credenciais recursos e, para receber uma ocorrência em cache, eles devem corresponder. Caso contrário, você acabará buscar o recurso duas vezes. Não é preciso dizer que a busca dupla é ruim, porque desperdiça a largura de banda do usuário e o faz esperar mais tempo, sem um bom motivo.

Para tags <script> e <link>, é possível definir o modo de credenciais com o crossorigin . No entanto, uma <script type="module"> sem O atributo crossorigin indica um modo de credenciais de omit, que não existe para <link rel="preload">. Isso significa que você precisaria mude o atributo crossorigin no <script> e no <link> para um dos outros valores, e talvez não tenha uma maneira fácil de fazer isso se o que você estiver tentar pré-carregar é uma dependência de outros módulos.

Além disso, buscar o arquivo é apenas a primeira etapa para realmente executar o código. Primeiro, o navegador precisa analisá-lo e compilá-lo. Idealmente, isso também precisa acontecer com antecedência para que, quando o módulo for necessário, o código e pronto para ser executado. No entanto, o V8 (mecanismo JavaScript do Chrome) analisa e compila módulos. diferente de outros JavaScript. <link rel="preload"> não oferecem alguma forma de indicar que o arquivo sendo carregado é um módulo, de modo que todos os pode fazer é carregar o arquivo e colocá-lo no cache. Assim que o script for carregado usando uma tag <script type="module"> (ou se ela for carregada por outro módulo), o navegador analisará e compila o código como um módulo JavaScript.

Em poucas palavras, sim. Com um tipo link específico para o pré-carregamento de módulos, podemos escrever HTML simples sem se preocupar com o modo de credenciais que estamos usando. A os padrões do Kubernetes simplesmente funcionam.

<head>
  <link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">

E, como o navegador agora sabe que o que você está pré-carregando é um módulo, pode ser inteligente e analisar e compilar o módulo assim que a busca for concluída, em vez de esperar até que ele seja executado.

Compatibilidade com navegadores

  • Chrome: 66.
  • Borda: ≤ 79.
  • Firefox: 115
  • Safari: 17.

Origem

Mas e os módulos dependências?

Engraçado você perguntar isso! Há, de fato, algo que não foi abordado neste artigo: recursão.

A especificação <link rel="modulepreload"> permite o carregamento opcional, não apenas módulo solicitado, mas também toda a árvore de dependências. Os navegadores não precisam podem fazer isso, mas conseguem.

Qual seria a melhor solução para pré-carregar um módulo e os respectivos árvore de dependências, já que você precisará da árvore de dependências completa para executar o aplicativo?

Os navegadores que optam por pré-carregar dependências recursivamente devem ter uma eliminação de duplicação robusta módulos. Portanto, em geral, a melhor prática seria declarar o módulo e a lista simples das dependências e confiar no navegador para não buscar o mesmo módulo duas vezes.

<head>
  <!-- dog.js imports dog-head.js, which in turn imports
       dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
  <link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
  <link rel="modulepreload" href="dog-head-mouth.mjs">
  <link rel="modulepreload" href="dog-head.mjs">
  <link rel="modulepreload" href="dog.mjs">
</head>

O pré-carregamento de módulos ajuda no desempenho?

O pré-carregamento pode ajudar a maximizar o uso da largura de banda, informando ao navegador o que ele precisa buscar para que não fique preso a nada durante aquelas longas idas e voltas. Se você estiver testando módulos e tiver problemas de desempenho devido a árvores de dependência, a criação de uma lista simples de pré-carregamentos pode definitivamente ajudar.

Como o desempenho do módulo ainda está sendo aprimorado, você confere mais de perto o que está acontecendo no seu aplicativo com as Ferramentas para desenvolvedores e considere agrupar seu aplicativo em vários blocos enquanto isso. Há muitos trabalho contínuo do módulo acontecendo no Chrome, então estamos nos aproximando de oferecer bundlers seu merecido descanso!