Otimização e eliminação de código com webpack e Babeljs
Com a velocidade a qual o JavaScript avança, tendo versões anuais acrescentando funcionalidades, acabamos por adicionar um compilador (Babeljs o mais comum deles) em nosso workflow para usufruirmos de todas essas novidades e mantermos a compatibilidade, e isso não tem problema nenhum.
Junto ao compilador é comum usarmos também um bundler que se encarrega de gerar nosso código final aplicando diversas otimizações. O webpack é um dos mais conhecidos bundlers JavaScript atualmente, e ele por si só já oferece várias opções de otimização, mas temos que estar atentos às nossas configurações.
O webpack oferece uma funcionalidade chamada tree shaking. Ela é responsável por eliminação de código não utilizado no nosso bundle. Porém, com a utilização do babel-loader, precisamos configura-ló corretamente para não perder essa funcionalidade.
Como exemplo, vamos entender qual é o problema, para depois entendermos a solução.
Aqui basicamente é um exemplo com módulos JavaScript:
// module.js
export const say = () => console.log('Say something')
export const scream = () => console.log('SCREAM SOMETHING')
// index.js
import { scream } from './module.js'
scream()
No index.js
importamos somente a função scream
do arquivo module.js
. Como nossa
aplicação não usa a função say
, não faz sentido adicioná-la ao nosso bundle, e é
isso o que faz o tree shaking do webpack. Porém nosso módulo utiliza algumas coisas
que precisam ser compiladas pelo Babeljs para não preocuparmos com retrocompatibilidade,
e é ai que temos que ter cuidado.
Geralmente nossa configuração do Babeljs é essa:
{
"presets": ["env"]
}
A única mudança que precisamos é setar o modules para false
.
{
"presets": [
[
"env",
{
"modules": false
}
]
]
}
O que acontece é que o Babeljs compila o arquivo antes do webpack, e ele converte os módulos para CommonJS por default, e quando chega no webpack ele não consegue usufruir dos módulos nativos do JavaScript.
Esse é um exemplo simples, mas quando sua aplicação cresce e utiliza muitas libs, não faz sentido onerar muito o carregamento com código não utilizado.
Agora uma outra dica: muitos dos presets do Babeljs possuem um parâmetro chamado
loose
, e o babel-preset-env é um deles.
Basicamente o que acontece na compilação do Babeljs é que quando ele encontra uma
funcionalidade não suportada na versão es5
, ele compila essa parte do código para es5
mantendo a funcionalidade e semântica do código fonte no código compilado. O que o
loose mode
faz é compilar para es5, porém não se importando tanto para a semântica,
e muitas vezes ele gera um código muito menor. Como o nosso bundle vai ser interpretado
diretamente no navegador ou no nodejs, não precisamos nos importar tanto com a
semântica aqui, já que continuamos dando manutenção no arquivo fonte.
Para habilitar:
{
"presets": [
[
"env",
{
"modules": false,
"loose": true
}
]
]
}
Para alguns exemplos de código gerado pelo loose mode
leia
Babel: Loose mode.
PS. Sugiro cuidado com
loose mode
, em alguns casos o código gerado pode modificar a funcionalidade.