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">
<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>
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.
Por que <link rel="preload">
não funciona com 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.
Então, o <link rel="modulepreload">
é apenas <link rel="preload">
para módulos?
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.
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!