Bundling de JavaScript no Magento 2: o que realmente acelera
Uma loja Luma carrega muito JavaScript. Numa página de produto é normal ver bem mais de cem módulos RequireJS pedidos um a um, cada um um arquivo pequeno. O bundling promete resolver isso agrupando-os em menos arquivos, maiores. A opção nativa muitas vezes piora as coisas, e as opções que ajudam exigem mais setup.
Este artigo cobre o que o Magento 2.4.8 oferece de fábrica, por que o bundling padrão é uma má escolha para a maioria das lojas, o que o Magepack faz de diferente e como medir se alguma dessas coisas ajuda.
Por que o Luma carrega tantos arquivos
O Luma usa RequireJS, que carrega módulos sob demanda. Um template declara um componente por data-mage-init ou text/x-magento-init, o RequireJS o busca, lê as dependências, busca essas, e assim por diante. Cada nível da árvore de dependências adiciona uma ida e volta antes que os próximos arquivos possam ser pedidos.
Com HTTP/2, muitas requisições pequenas custam menos do que custavam, porque compartilham uma conexão. As idas e voltas causadas pela cadeia de dependências continuam, porém. O navegador não consegue pedir um módulo que ainda não sabe que precisa.
As opções nativas
Todas ficam em Stores, Configuration, Advanced, Developer, e essa seção só é visível em developer mode. Em production mode, defina pela CLI:
bin/magento config:set dev/js/minify_files 1
bin/magento config:set dev/js/merge_files 0
bin/magento config:set dev/js/enable_js_bundling 0
bin/magento config:set dev/js/move_script_to_bottom 1
bin/magento config:set dev/css/minify_files 1
bin/magento config:set dev/template/minify_html 1
Os valores acima são um ponto de partida razoável para muitas lojas Luma, não uma resposta universal. Cada opção merece um olhar mais de perto.
Minificação
O dev/js/minify_files serve versões minificadas dos arquivos JavaScript. Reduz o tamanho da transferência sem desvantagem real depois que o seu código funciona. Deixe ativado em produção.
Merge
O dev/js/merge_files junta os scripts declarados nas seções head do layout XML em um arquivo só. Ele não toca nos módulos RequireJS, que são a maior parte do JavaScript, então o ganho é pequeno. Em HTTP/2 geralmente não vale a pena ativar.
Bundling nativo
O dev/js/enable_js_bundling agrupa módulos RequireJS em arquivos de bundle durante o static content deploy. O problema é como ele agrupa. Ele empacota os módulos do tema inteiro em bundles de um tamanho configurado, sem saber qual página precisa de qual módulo. O navegador então baixa todos os bundles em toda página, incluindo código do checkout, da conta do cliente e de widgets que o visitante nunca vê.
O tamanho do bundle e as exclusões são definidos no etc/view.xml do tema:
<vars module="Js_Bundle">
<var name="bundle_size">1MB</var>
</vars>
<exclude>
<item type="file">Lib::jquery/jquery.min.js</item>
<item type="directory">Lib::tiny_mce</item>
</exclude>
Excluir bibliotecas grandes que você só usa em poucas páginas ajuda, mas não resolve o problema de design. Na maioria das lojas eu deixaria o bundling nativo desligado e só o testaria como um experimento medido.
Move scripts to bottom
O dev/js/move_script_to_bottom move as tags de script inline e externas para o fim do body. Pode ajudar nos tempos de renderização, mas quebra scripts inline que esperam uma biblioteca carregada antes deles. Teste o checkout completo e qualquer widget de terceiros depois de ativar.
Magepack: bundling por tipo de página
O Magepack é uma ferramenta open source da Creativestyle que adota outra abordagem. Ele carrega páginas reais da sua loja num navegador headless, registra quais módulos RequireJS cada tipo de página usa e monta os bundles a partir disso:
- um bundle comum com os módulos que todo tipo de página usa
- um bundle para páginas CMS
- um bundle para páginas de categoria
- um bundle para páginas de produto
- um bundle para o checkout
Cada página então carrega o bundle comum mais o seu próprio, em vez de uma longa cadeia de arquivos individuais. Ele precisa de um módulo Magento complementar que adiciona os bundles às páginas certas. O fluxo é:
npm install -g magepack
magepack generate \
--cms-url="https://shop.example.test/" \
--category-url="https://shop.example.test/women/tops.html" \
--product-url="https://shop.example.test/some-product.html"
magepack bundle
O generate escreve um arquivo magepack.config.js que você commita no repositório. O bundle roda depois do static content deploy a cada build e cria os arquivos de bundle dentro de pub/static para cada tema e locale. Confira o README do projeto para o nome exato do módulo e o suporte a versões do Magento antes de instalar, porque ferramentas da comunidade mudam mais rápido que o core.
Pontos de atenção:
- A etapa generate precisa de URLs reais com conteúdo típico. Se a sua página de produto tem widgets opcionais só em alguns produtos, escolha um produto que os tenha.
- Gere a config de novo depois de adicionar módulos que mudam o JavaScript do frontend. Senão os módulos novos são carregados do jeito antigo, o que ainda funciona mas perde o ganho.
- Mantenha a etapa de bundle no pipeline de deploy. Um deploy que a pule deixa a loja sem bundles, o que ainda funciona, só mais devagar.
Bundling avançado com r.js
A Adobe documenta uma abordagem de bundling avançado usando o otimizador do RequireJS, o r.js, com uma configuração escrita à mão por tipo de página. É a mesma ideia do Magepack, mas você mantém as listas de módulos por conta própria. Dá controle total e custa muita manutenção. Para a maioria dos times, o Magepack é a versão prática disso.
Como medir
Mudanças de bundling são fáceis de errar nas duas direções, então meça antes e depois nas mesmas páginas, com o cache aquecido:
- Escolha uma home, uma página de categoria, uma página de produto e o cart.
- Rode o Lighthouse no Chrome DevTools ou o WebPageTest com throttling mobile, várias execuções cada, e anote a mediana.
- Olhe o Total Blocking Time e o tempo até a página ficar interativa, não só a nota.
- Abra a aba Coverage do DevTools para ver quanto do JavaScript carregado não é usado em cada página.
- Depois do release, acompanhe por algumas semanas os dados de usuários reais no relatório de Core Web Vitals do Search Console.
Se o Coverage mostrar que a maior parte do JavaScript não é usada, o bundling tem um teto. O guia de Core Web Vitals cobre as outras frentes, como adiar scripts de terceiros e reduzir o que roda no carregamento.
Notas de deploy
Nada disso funciona em developer mode, onde os arquivos são servidos individualmente para você poder depurá-los. Bundling, minificação e merge só têm efeito em production mode depois do bin/magento setup:static-content:deploy. Garanta que o servidor de build e o de produção usem os mesmos valores de configuração, ou guarde-os no app/etc/config.php definindo com bin/magento config:set --lock-config. O artigo de deploy em production mode cobre as etapas de build.
Quando parar de otimizar o JavaScript do Luma
O bundling reduz o custo de carregar o JavaScript do Luma. Ele não reduz a quantidade de JavaScript que precisa rodar, e em celulares intermediários o tempo de execução costuma ser o problema maior. Se você já ativou a minificação, configurou o Magepack e adiou as tags de terceiros, e a loja continua lenta no mobile, o próximo passo é um frontend com menos JavaScript. A comparação Hyvä vs Luma trata dessa decisão.
FAQ
Devo ativar o bundling de JS nativo do Magento?
Em geral não. Ele agrupa todos os módulos do tema sem saber qual página precisa deles, então toda página baixa código que nunca usa. Meça se quiser, mas o bundling por página com uma ferramenta como o Magepack é a melhor opção.
O merge de JS ajuda em HTTP/2?
Muito pouco. Ele só junta os scripts declarados nas seções head do layout, não os módulos RequireJS, e o HTTP/2 já reduz o custo de requisições separadas.
Por que minhas configurações de bundling não mudam nada?
A loja está em developer mode, ou o static content não foi deployado de novo depois da mudança. Essas configurações só se aplicam aos arquivos gerados pelo setup:static-content:deploy em production mode.
O Magepack é seguro para o checkout?
Ele pode fazer bundle dos módulos do checkout, mas teste o checkout completo com todos os métodos de pagamento depois. Se algo quebrar, você pode excluir o checkout do bundling e manter os ganhos nas páginas de catálogo.
Atendo como freelancer em Magento e Adobe Commerce, incluindo auditorias de performance de frontend em lojas Luma. Se você precisa de ajuda com isso, fale comigo.
Artigos relacionados
Customer data sections no Magento 2: como funciona o conteúdo privado
Como as customer data sections mantêm páginas em cache personalizadas: sections.xml, section sources, customer-data.js, invalidação e os erros que quebram o FPC.
Mixins do RequireJS no Magento 2: estenda o JS do core sem override
Como escrever mixins do RequireJS no Magento 2 para UI components, widgets jQuery e módulos de função, como depurar e quando um map é melhor.
Magento 2: tipos de cache, clean, flush e cache type próprio
O que cada cache type do Magento 2 guarda, a diferença real entre cache:clean e cache:flush, caches invalidados e como criar seu próprio cache type.
Core Web Vitals no Magento 2: como corrigir LCP, INP e CLS
Onde lojas Magento 2 com Luma perdem nos Core Web Vitals e como corrigir LCP, INP e CLS: resposta do servidor, CSS, fontes, imagens, galeria e scripts de terceiros.