Introdução ao Webpack – parte 1

Hoje é muito comum, ao criar um projeto web, ter algum tipo de build process, ou processo de construção, para ajudar nas tarefas de desenvolvimento e preparar os arquivos para o ambiente de produção.

Você pode utilizar o Grunt ou o Gulp para isso, criando uma corrente de transformações que permite, com um código, gerar arquivos CSS e JavaScript minificados.

Essas ferramentas são extremamente populares e muito úteis. No entanto, existe outra maneira de fazer isso, com o Webpack.

O Webpack é conhecido pelo que chamamos de “module bundler”. Ele agrega os módulos JavaScript, compreende suas dependências, e concatena todos da maneira mais eficiente possível, retornando apenas um arquivo JS. Nada de especial até aqui, certo? Soluções como o RequireJS tem feito isso há anos.

Bom, essa é a diferença.  Com o Webpack, módulos não ficam restritos a arquivos JavaScript. Utilizando Loaders, o Webpack compreende que um módulo JavaScript pode requisitar um arquivo CSS, e que aquele CSS pode requisitar uma imagem. Os recursos gerados vão conter apenas o que é necessário, com o mínimo de interferência. Vamos fazer um teste para ver o Webpack em ação.

Como a maioria das ferramentas para desenvolvimento web, você vai precisar do Node.js instalado antes de continuar. Quando estiver tudo pronto, tudo que você precisa fazer é instalar o Webpack executando o seguinte comando no terminal.

npm install webpack -g

Aqui, a parte importante é a referência ao arquivo bundle.js, que é o que o Webpack vai fazer para nós. Também se atente ao elemento H2; vamos utilizar ele mais tarde.

Agora, crie dois arquivos no mesmo diretório do arquivo HTML. Nomeie o primeiro como main.js, este vai ser o ponto de partida para o nosso script. Depois nomeie o segundo como say-hello.js. Este vai representar um simples módulo que agrega o nome de uma pessoa e um elemento no DOM, e insere uma mensagem de boas vindas.

// say-hello.js

module.exports = function (name, element) {
element.textContent = 'Hello ' + name + '!';
};

Agora que temos um módulo, podemos requisita-lo a partir do arquivo main.js. É bem simples, conforme o exemplo:

var sayHello = require('./say-hello');

sayHello('Guybrush', document.querySelector('h2'));

Agora se abrirmos nosso arquivo HTML vamos notar que a mensagem, obviamente, não é apresentada, pois não incluímos o arquivo main.js então não compilamos as dependências para o navegador. O que precisamos fazer é apontar o Webpack para o arquivo main.js para que ele analise se existe alguma dependência. Caso tenha, ele compila tudo e cria o arquivo bundle.js que utilizamos no navegador.

Vamos voltar ao terminal para executar o Webpack. Execute o comando:

webpack main.js bundle.js

No primeiro item especificamos o arquivo que desejamos que o Webpack procure dependências. Ele vai operar mesmo que um arquivo requisite outro, até que passar por todas as dependências. Feito isso, o Webpack devolve as dependências como um único arquivo, neste caso o arquivo bundle.js. Se você pressionar Enter, vai ver algo parecido com isso:

Hash: 3d7d7339a68244b03c68
Version: webpack 1.12.12
Time: 55ms
Asset Size Chunks Chunk Names
bundle.js 1.65 kB 0 [emitted] main
[0] ./main.js 90 bytes {0} [built]
[1] ./say-hello.js 94 bytes {0} [built]

Agora execute o arquivo index.html para ver a mensagem de “saying hello” na página.

Não é muito divertido utilizar um comando do Webpack apenas para gerar arquivos. Por isso, o Webpack nos permite utilizar um arquivo de configuração. Crie um arquivo chamado webpack.config.js na raiz do seu projeto com o seguinte conteúdo:

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    }
};

Agora podemos digitar apenas webpack no terminal, e obter o mesmo resultado.

O que é isso? Não está curtindo digitar webpack sempre que você altera um arquivo? Vamos configurar um servidor simples para deixar as coisas mais eficientes. No terminal, digite o comando:

npm install webpack-dev-server -g

Depois, execute o comando webpack-dev-server. Com isso iniciamo um simples servidor web, utilizando o diretório em questão para servir o arquivos. Abre uma nova janela no navegador e acesso o endereço http://localhost:8080/webpack-dev-server/. Se tudo der certo, você vai ver algo como isso:

An example of the server

Agora, não só temos um servidor web, temos um servidor web que observa mudanças no nosso código. Se ele detectar alguma alteração de arquivo no diretório, automaticamente o comando webpack é executado, e a página é atualizada, sem que precisemos fazer nada. Tudo isso com nenhuma configuração.

Faça um teste, mude o nome que inserimos na função sayHello, e volte no navegador para confirmar se a mudança foi aplicada.

Um dos recursos mais importantes do Webpack são os Loaders. Loaders podem ser interpretados como “tarefas” no Grunt ou no Gulp. Eles basicamente transformam o arquivo de alguma maneira antes de criar o arquivo final.

Imagine que desejamos utilizar alguns recursos do ES2015 no nosso código. ES2015 é uma nova versão do JavaScript que ainda não tem suporte em todos os navegadores, então precisamos de um loader para transformar todo código ES2015 para o antigo ES5, que tem suporte. Para isso, podemos utilizar o popular Babel Loader que, de acordo com as instruções, pode ser instalado com o comando:

npm install babel-loader babel-core babel-preset-es2015 --save-dev

Este comando vai instalar o loader e suas dependências, além do preset do ES2015, necessário para que o Babel saiba qual tipo de JavaScript está convertendo.

Agora que o loader está instalado, precisamos apenas configurar o Babel para utiliza-lo.  Atualize o arquivo webpack.config.js conforme o exemplo abaixo:

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015']
            }
        }],
    }
};

Algumas notas importantes aqui. A primeira linha test: /\.js$/, nada mais é que do que uma expressão que aplica este loader para todos os arquivos com extensão .js. Da mesma forma, o exclude: /node_modules/, diz ao Webpack para ignorar o diretório node_modules. O loader e o query não simples de entender – utilizamos o loader babel com o preset ES2015.

Reinicie o servidor pressionando ctrl+c e executando o comando webpack-dev-server novamente. Agora vamos utilizar um pouco de código ES6 para testar o recurso. Que tal mudar a variável sayHello para uma constante?

const sayHello = require('./say-hello')

Após salvar, o Webpack deve recompilar e carregar novamente a página automaticamente. Você não vai notar nenhuma diferença de qualquer forma. Dê uma olhada no arquivo bundle.js e veja se consegue encontrar a palavra const. Se o Webpack e o Babel fizeram suas tarefas corretamente, você não vai encontrar em lugar algum – apenas o JavaScript padrão.

Na segunda parte do tutorial, vamos analisar como utilizar o Webpack para adicionar CSS e imagens em uma página, além de preparar a página para deploy (produção).

  • Bernardo Gomes

    Muito bom o artigo
    Está de parabéns.

    Tenho uma pergunta.
    Qual é a vantagem de utilizar webpack?

    • Opa Bernardo,
      na verdade não é que tem vantagem, ele é diferente do grunt e do gulp, ele é um bundler, mesmo fazendo mais que isso.
      O grunt e o gulp gerenciam tarefas.