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

Arquivo module.js

export const say = () => console.log('Say something')

export const scream = () => console.log('SCREAM SOMETHING')

Arquivo 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.

Boas práticas e automatização de tarefas no Front-end

Palestra onde apresento boas práticas de desenvolvimento para o front-end.

Links