Como acelerar seu app Next.js com divisão de código e estratégias de carregamento inteligentes.
Publicado em: 8 de novembro de 2019
Saiba mais sobre os diferentes tipos de divisão de código e como usar importações dinâmicas para acelerar seus apps Next.js.
Divisão de código com base em rota e componente
Por padrão, o Next.js divide seu JavaScript em partes separadas para cada rota. Quando os usuários carregam seu aplicativo, o Next.js envia apenas o código necessário para a rota inicial. Quando os usuários navegam pelo aplicativo, eles buscam os trechos associados às outras rotas. A divisão de código com base em rotas minimiza a quantidade de script que precisa ser analisada e compilada de uma só vez, o que resulta em tempos de carregamento de página mais rápidos.
Embora a divisão de código com base em rotas seja um bom padrão, é possível otimizar ainda mais o processo de carregamento com a divisão de código no nível do componente. Se você tiver componentes grandes no seu app, divida-os em partes separadas. Assim, todos os componentes grandes que não são essenciais ou que só são renderizados em determinadas interações do usuário (como clicar em um botão) podem ser carregados de forma lenta.
O Next.js é compatível com import() dinâmicos,
que permitem importar módulos JavaScript (incluindo componentes do React)
de forma dinâmica e carregar cada importação como um bloco separado. Isso oferece
divisão de código no nível do componente e permite controlar o carregamento de recursos para que
os usuários façam o download apenas do código necessário para a parte do site que
estão visualizando. No Next.js, esses componentes são renderizados do lado do servidor
(SSR)
por padrão.
Importações dinâmicas em ação
Esta postagem inclui várias versões de um app de exemplo que consiste em uma página simples com um botão. Ao clicar no botão, você vê um cachorrinho fofo. Ao passar por cada versão do app, você vai entender como as importações dinâmicas são diferentes das estáticas e como trabalhar com elas.
Na primeira versão do app, o cachorrinho mora em components/Puppy.js. Para
mostrar o cachorrinho na página, o app importa o componente Puppy em
index.js com uma instrução de importação estática:
import Puppy from "../components/Puppy";
Para ver como o Next.js agrupa o app, inspecione o rastreamento de rede no DevTools:
Para visualizar o site, pressione Ver app e depois Tela cheia
.
Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
Clique na guia Rede.
Marque a caixa de seleção Desativar cache.
Atualize a página.
Quando você carrega a página, todo o código necessário, incluindo o componente Puppy.js, é agrupado em index.js:
Quando você pressiona o botão Clique em mim, apenas a solicitação do JPEG do cachorrinho é adicionada à guia Rede:
A desvantagem dessa abordagem é que, mesmo que os usuários não cliquem no botão para
ver o cachorrinho, eles precisam carregar o componente Puppy porque ele está incluído em
index.js. Neste pequeno exemplo, isso não é um grande problema, mas em aplicativos do mundo real, geralmente é uma grande melhoria carregar componentes grandes apenas quando necessário.
Agora confira uma segunda versão do app, em que a importação estática é
substituída por uma importação dinâmica. O Next.js inclui o next/dynamic, que permite usar importações dinâmicas para qualquer componente no Next:
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
Siga as etapas do primeiro exemplo para inspecionar o rastreamento de rede.
Quando você carrega o app pela primeira vez, apenas index.js é baixado. Desta vez, ele é 0,5 KB menor (diminuiu de 37,9 KB para 37,4 KB) porque não inclui o código do componente Puppy:
O componente Puppy agora está em um bloco separado, 1.js, que é carregado apenas
quando você pressiona o botão:
Em aplicativos do mundo real, os componentes costumam ser muito maiores, e o carregamento lento deles pode reduzir a carga útil inicial do JavaScript em centenas de kilobytes.
Importações dinâmicas com indicador de carregamento personalizado
Ao carregar recursos de forma lenta, é recomendável fornecer um indicador de carregamento
caso haja atrasos. No Next.js, isso pode ser feito fornecendo um
argumento adicional à função dynamic():
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
Para ver o indicador de carregamento em ação, simule uma conexão de rede lenta no DevTools:
Para visualizar o site, pressione Ver app e depois Tela cheia
.
Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
Clique na guia Rede.
Marque a caixa de seleção Desativar cache.
Na lista suspensa Limitação, selecione 3G rápido.
Pressione o botão Clique aqui.
Agora, quando você clica no botão, leva um tempo para carregar o componente, e o app mostra a mensagem "Carregando…" enquanto isso.
Importações dinâmicas sem SSR
Se você precisar renderizar um componente apenas no lado do cliente (por exemplo, um widget de chat), defina a opção ssr como false:
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
Conclusão
Com suporte para importações dinâmicas, o Next.js oferece divisão de código no nível do componente, o que pode minimizar os payloads JavaScript e melhorar o tempo de carregamento do aplicativo. Por padrão, todos os componentes são renderizados no lado do servidor, e você pode desativar essa opção sempre que necessário.