Webpack sem Medo — Parte 1: Introdução 
Tags: webpack
Published: 2020-04-02 18:28:58

---
title: Webpack sem Medo — Parte 1: Introdução 
published: true
description: Esta série tem o objetivo de apresentar as funcionalidades do webpack de forma gradativa, explicando conceitos e mostrando exemplos.
tags: webpack
canonical_url: https://www.webdevdrops.com/webpack-sem-medo-introducao-af889eb659e7/
cover_image: https://www.webdevdrops.com/wp-content/uploads/2018/10/webpack-sem-medo.png
---

Esta série tem o objetivo de apresentar as funcionalidades do [**webpack**](https://webpack.js.org/) de forma gradativa, explicando conceitos e mostrando exemplos.

> **Por que “sem medo”?**
> Conheço algumas pessoas (incluindo eu mesmo) que tiveram um primeiro contato com **webpack**, não entenderam direito como usar, ficaram mais confusas ainda lendo a documentação e criaram uma aversão à ferramenta.
> Muitas dessas pessoas tiveram contato com a versão 1 do **webpack**, que tinha uma configuração mais confusa e uma documentação menos organizada.
> A boa notícia é que a partir da versão 2 isso mudou radicalmente. A configuração ficou mais fácil de compreender, e a documentação foi completamente reescrita, com excelentes guias, explicações claras e completas.
> **Se tinha medo do webpack, a hora de perder o medo é essa!**

Mas o que é webpack?
--------------------

![](https://www.webdevdrops.com/wp-content/uploads/2019/10/webpack-1.png)

**webpack** é um *module bundler* (empacotador de módulos) para JavaScript, em outras palavras, ele junta os arquivos JS (e também outros formatos) da sua aplicação (seja arquivos seus ou dependências externas) em um arquivo só (ou mais de um), de forma otimizada. Os arquivos são unificados na ordem certa, sem duplicação e podem ser minificados para reduzir o tamanho.

Um ponto forte do **webpack** que ele é altamente configurável e extensível através de plugins. Isso permite fazer algumas coisas interessantes como:

- Utilizar **outros sabores de JS**, como ES6+, TypeScript, JSX e fazer a transpilação (conversão para ES5) automaticamente no processo de empacotamento.
- Tratar e **empacotar outros tipos de arquivos**, como CSS (e variações como SASS, LESS, Stylus), SVG, imagens, arquivos de templates (Pug, Handlebars).
- E muito mais, como veremos mais pra frente…

Grafo de dependências
---------------------

Como o **webpack** sabe quais arquivos incluir e em qual ordem? Ele monta um **grafo de dependências**, que é uma estrutura mais ou menos assim:

![](https://www.webdevdrops.com/wp-content/uploads/2019/10/webpack-2.png)

Partindo de um arquivo inicial (entrada), ele verifica quais outros arquivos são importados por este, e os adiciona ao grafo. Para cada um desses ele também verifica quais eles importam, assim sucessivamente até que o grafo contenha todos os arquivos (módulos) necessários para a aplicação.

Módulos
-------

Para indicar que um arquivo JS depende de outro, ele precisa importá-lo. Ex.:

```javascript
import React from 'react'
import utils from './utils'
```


No exemplo acima ele importa uma dependência externa (**React**) e uma interna (o caminho começa com `./`). Note também que não é necessário informar a extensão do arquivo se for JS.

O arquivo que vai ser importado, em contrapartida, precisa indicar o que ele exporta. Ex.:

```javascript
const utils = { ... }  
export default utils
```


Cada arquivo desses, que exporta algum dado ou funcionalidade, é chamado de **módulo**.

Dividir sua aplicação em módulos é uma boa prática, pelos seguintes benefícios:

- **Manutenibilidade**: as funcionalidades ficam menos acopladas, é mais fácil alterar uma parte do código sem afetar o sistema inteiro.
- **Isolamento**: variáveis e funções declaradas dentro de um módulo são acessíveis apenas dentro dele (exceto aquilo que o módulo explicitamente exporta), evitando conflitos de variáveis e acesso desnecessário de uma parte do código a outra não relacionada.
- **Reusabilidade**: um módulo com uma funcionalidade bem definida, é como uma peça de lego, pode ser reutilizada em outras partes do mesmo sistema, ou em outros sistemas.
- **Testabilidade**: com o código menos acoplado, fica mais fácil escrever testes unitários para validar cada funcionalidade.

A forma de fazer *import/export* mostrada acima usa o padrão **ES Modules**, que é o adotado a partir do ES6 nos navegadores. O Node.js atualmente usa o padrão **CommonJS**, que muda um pouco a sintaxe:

```javascript
const express = require('express')  
const utils = require('./utils')

module.exports = ...
```


Ambas as sintaxes são suportadas pelo webpack, mas aqui vamos usar **ES Modules**, que é o padrão no navegador, e está caminhando para se tornar o padrão no Node.js (veja referência \[8\]).

> **Leitura importante**
> Recomendo se familiarizar com a sintaxe do **ES Modules**, e as diferentes formas de import/export. Veja referências \[5\], \[6\] e \[7\] ao final do artigo.

Os 4 conceitos fundamentais do webpack
--------------------------------------

Antes de começar a colocar a mão na massa é importante compreender os **4 *core concepts*** do webpack: **entry**, **output**, **loaders** e **plugins**. Tendo estes conceitos em mente fica mais fácil entender como o webpack trabalha.

![](https://www.webdevdrops.com/wp-content/uploads/2019/10/webpack-3.png)

Nesta primeira parte vamos ver apenas os dois primeiros, que já serão suficientes para os primeiros exemplos. Veremos os outros quando forem necessários.

### Entry (entrada)

Lembra que eu falei lá em cima sobre o **grafo de dependências**, e que para montá-lo o webpack parte de um **arquivo inicial** e vai seguindo os *imports*? Pois é, este arquivo inicial é o *entry point* (ponto de entrada) da aplicação.

Veremos que toda configuração de webpack possui pelo menos um *entry point*. Pode ter mais de um (nesse caso serão gerados mais de um grafo de dependências), mas vamos ver esses casos mais avançados em outro momento.

### Output (saída)

Uma vez montado o grafo de dependências, o webpack precisa saber onde ele vai salvar o arquivo unificado, ou vários arquivos, dependendo da configuração.

- - - - - -

Exemplo 1: Minificação de JS
----------------------------

Vamos ver na prática o exemplo mais básico de um setup de webpack, com apenas uma entrada e uma saída. Vamos pegar uma aplicação divida em arquivos JS (módulos) e gerar um arquivo único.

Este exemplo completo pode ser encontrado aqui: <https://github.com/doug2k1/webpack-scenarios/tree/master/1-basic>

### Pré-requisitos

- Possuir [Node.js](https://nodejs.org) instalado (de preferência uma versão recente)
- Conhecimento básico de terminal/linha de comando (saber navegar entre pastas e executar comandos simples)

### Instalação

Inicializar o arquivo *package.json* para gerenciar dependências, caso sua aplicação ainda não possua. Rode no terminal, na raiz da aplicação:

```
npm init -y
```
Instalar o webpack e o webpack-cli (que é o utilitário de linha de comando do webpack):

```
npm i -D webpack webpack-cli
```
Usamos `-D` para salvar o webpack nas dependências de desenvolvimento (*devDependencies*), já que ele só vai ser usado durante o desenvolvimento. Serão criadas as entradas abaixo no *package.json* (a versão pode ser diferente, dependendo de qual versão é a mais recente quando você executar o comando):

```json
"devDependencies": {  
  "webpack": "^4.20.2",  
  "webpack-cli": "^3.1.2"  
}
```


A estrutura de pastas vai ficar assim:

```
|-- node_modules  
|-- package.json  
|-- package-lock.json
```
Explicando: *node\_modules* é a pasta que guarda todos os arquivos baixados das dependências instaladas, *package.json* é onde listamos as dependências e versões (entre outras informações da aplicação) e *package-lock.json* é um arquivo que “trava” as versões das dependências. Quando outros desenvolvedores executarem `npm i` para baixar as dependências, este arquivo garante que serão instaladas as mesmas versões para todo mundo.

### Zero Config

Vou mostrar daqui a pouco como configurar o webpack usando um arquivo de configuração, mas para este exemplo simples você nem vai precisar deste arquivo.

### Arquivos da aplicação

Por enquanto o projeto ainda não tem nenhum arquivo da aplicação em si. Uma prática comum é colocar o código-fonte da aplicação em uma pasta `src`. Primeiro vamos criar um `index.js` nesta pasta como nosso ponto de entrada:

```
|-- src  
  |-- index.js
```
Com o conteúdo:

```javascript
import cow from './cow'  
  
document.querySelector('#box').innerText = cow.say('Webpack is great!')
```


Este arquivo importa outro arquivo que está na mesma pasta, o *cow.js* (`./` significa “mesma pasta do arquivo atual”). Vamos agora criar este outro arquivo:

```
|-- src  
  |-- index.js  
  |-- cow.js
```
Com o conteúdo:

```javascript
import cowsay from 'cowsay-browser'

export default {  
  say: function (str) {  
    return cowsay.say({ text: str })  
  }  
}
```


Veja que este arquivo já importa uma dependência externa (nome da dependência, sem `./`). Precisamos usar o NPM para instalá-la:

```
npm i -S cowsay-browser
```
Aqui usamos `-S` para salvar a dependência no *package.json* como dependência normal, isto é, que será usada pela aplicação final. Vai ser adicionada esta entrada:

```json
"dependencies": {  
  "cowsay-browser": "^1.1.8"  
}
```


### Arquivo HTML

Para ver o resultado no navegador, vamos precisar de um arquivo HTML. Vamos criar então um `index.html` na raiz da aplicação, com este conteúdo:

```markup
<!doctype html>  
<html>  
<head>  
  <title>Webpack</title>  
</head>  
<body>  
  <pre id="box">  
  <script src="dist/main.js"></script>  
</body>  
</html>
```


Veja que carrega um arquivo `dist/main.js` que ainda não temos. Este é o arquivo que o webpack vai gerar a partir de nossos fontes.

### Configurando o webpack

Por default, o webpack considera como ponto de entrada (***entry point***) o arquivo `src/index.js` e como arquivo de saída (***output***) `dist/main.js`. Por isto este primeiro exemplo não precisa de um arquivo de configuração.

Mas, se quiséssemos alterar o ***entry point*** ou o ***output***, poderíamos criar um arquivo `webpack.config.js` na raiz da aplicação com o conteúdo:

```javascript
const path = require('path')

module.exports = {  
  entry: './src/index.js',

  output: {  
    path: path.resolve('dist'),  
    filename: 'main.js'  
  }  
}
```


Veja que este arquivo é um módulo, que exporta um objeto. Aqui devemos usar o padrão **CommonJS**, pois este arquivo vai executar no Node.js, quando o webpack for acionado.

O primeiro item, **entry**, é o nosso ponto de entrada.

O segundo, **output**, é onde o webpack vai salvar o *bundle* gerado. Esta configuração pede o caminho da pasta (**path**) e o nome do arquivo (**filename**) separados. O caminho da pasta deve ser absoluto, por isso usamos a função [*path.resolve*](https://nodejs.org/api/path.html#path_path_resolve_paths) do Node para gerar um caminho absoluto a partir de um relativo.

### Gerando o bundle (Fazendo a magia acontecer)

Agora que o circo está montado, vamos gerar esse tal *main.js*! Para isso, vamos adicionar uma entrada no nosso *package.json*:

```json
"scripts": {  
  "build": "webpack"  
}
```


Com isso, basta executar no terminal:

```
npm run build
```
Este comando irá executar o webpack (através do webpack-cli), que vai percorrer o **grafo de dependências**, partindo do ***entry point***, e gerar o *main.js*, que contém todo o código da aplicação e das dependências.

![](https://www.webdevdrops.com/wp-content/uploads/2019/10/webpack-5.png)

Você pode abrir o *index.html* no navegador e ver o resultado.

![](https://www.webdevdrops.com/wp-content/uploads/2019/10/webpack-4.png)

### Modos: desenvolvimento e produção

Se você olhar o arquivo main.js gerado vai ver que ele está minificado (sem identação e quebras de linhas, com os nomes de variáveis alterados e com tamanho bem menor que os arquivos originais). Isso acontece porque o webpack, por padrão, roda em modo **produção** (***production***).

O modo ***production*** faz duas coisas por baixo dos panos:

- Ativa o plugin [**UglifyJS**](https://webpack.js.org/plugins/uglifyjs-webpack-plugin/) para minificar o bundle. O UglifyJS faz uma minificação agressiva. Além de remover espaços, quebras de linha e comentários, ele renomeia variáveis e faz transformações no código para deixar o mais curto possível.
- Seta a variável `process.env.NODE_ENV="production"`. Algumas bibliotecas olham esta variável, e se estiver com o valor “production” ativam algumas otimizações para produção.

O outro modo, **desenvolvimento** (***development***), não minifica o código, mas ele roda mais rápido. Ideal (como o nome diz) para usar enquanto ainda está desenvolvendo o código.

Para escolher o modo, basta passar a opção `--mode` para o webpack-cli:

```
webpack --mode development
```
### Opção watch

Legal, mas toda vez que alterar um JS vou precisar rodar este comando manualmente?

Não, jovem! Para isso tem a opção *watch*, onde o webpack vai ficar monitorando os arquivos e a cada alteração ele vai reconstruir o arquivo final.

Para isso basta passar a flag `-w` para o cli:

```
webpack -w
```
Com isso, para deixar o *workflow* mais versátil você pode definir dois scripts no *package.json*:

```json
"scripts": {  
  "build:watch": "webpack -w --mode development",  
  "build:prod": "webpack --mode production"  
},
```


Assim, durante o desenvolvimento você usa `npm run build:watch` para rodar em modo ***development*** com a opção *watch*, e para mandar o código para produção você usa `npm run build:prod`.

- - - - - -

O que vem pela frente
---------------------

Nos próximos artigos da série vamos falar de **loaders**, para tratar outros formatos de arquivos, **plugins**, para realizar diferentes tarefas e apresentar cenários mais avançados.

Feedbacks?
----------

Qualquer crítica ou sugestão, comente ou entre em contato.

Referências
-----------

- \[1\] <https://webpack.js.org/> — Site oficial do webpack (inglês). Toda a documentação, com excelentes guias. Sua melhor referência, se não tiver problemas com inglês.
- \[2\] <https://www.udemy.com/webpack-2-the-complete-developers-guide/learn/v4/overview> — Curso de webpack (inglês) na Udemy, com o excelente instrutor Stephen Grider. Geralmente rola promoção e este curso sai por R$20 ou R$30.
- \[3\] https://coderweb.com.br/webpack-e-complexo-mas-so-um-pouquinho/ — Artigo do Coder Web sobre webpack (offline).
- \[4\] <https://willianjusten.com.br/configurando-o-webpack-para-rodar-react-e-es6/> — Artigo do Willian Justen sobre webpack com React e ES6.
- \[5\] [http://exploringjs.com/es6/ch\_modules.html](http://exploringjs.com/es6/ch_modules.html) — Capítulo sobre ES Modules do livro *Exploring ES6* (inglês)
- \[6\] <https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/import> — Referência na MDN sobre import.
- \[7\] <https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/export> — Referência na MDN sobre export.
- \[8\] <https://blogs.windows.com/msedgedev/2017/08/10/es-modules-node-today/> — Post sobre o uso de ES Modules no Node.js (inglês)