Image for post
Image for post
Cada opção, um resultado diferente, ahh webpack!

As partes confusas do webpack

webpack, é o empacotador que está liderando os projetos em React e Redux. E eu acho que o pessoal do Angular 2 e outros frameworks também estão usando ele hoje em dia.

Quando eu vi o arquivo de configuração do webpack pela primeira vez, ele parecia um documento alien 👽 e muito confuso 😱.

Depois de brincar com ele um pouco, posso dizer agora, que é porquê o webpack tem uma sintaxe única e novas filosofias que podem causar confusão para iniciantes. Acidentalmente, essas filosofias também são responsáveis por torna-lo tão popular.

Já que é confuso iniciar e entender o webpack, eu vou escrever alguns posts e tentar tornar isso fácil para os outros começarem a usar todo seu potencial. Essa é a primeira parte.

A filosofia principal do webpack

webpack é baseado em duas idéias principais:

  1. Tudo é um módulo: Assim como arquivos JS podem ser “módulos”, tudo (CSS, imagens, HTML) pode ser um módulo. Isso é, você pode require(“meuArquivo.js”) ou require(“meuArquivo.css”). Isso quer dizer que você pode dividir qualquer artefato em pequenas e flexíveis partes, reusá-los e assim por diante.
  2. Carregar o que você precisa, quando você precisa: Normalmente, empacotadores de módulos pegam todos os módulos e geram um único arquivo final, como . Mas, em vários projetos do mundo real, esse arquivo final pode ser algo em torno de 10~15MB e pode temorar muito para carregar. webpack tem várias funcionalidades para dividir seu código e gerar múltiplos arquivos finais e também pode carregar partes do seu projeto assincronamente, assim, podendo carrregar o que você precisa, quando você precisa!

Certo, agora vamos olhar suas partes confusas…

1. Desenvolvimento x Produção

A primeira coisa para ficar atento, é que o webpack tem inúmeras funcionalidades. Algumas são apenas para desenvolvimento e outras apenas para produção e outras para ambos.

Image for post
Image for post
Um exemplo básico de configuração dev x prod.

Normalmente, a maioria dos projetos usam tantas funcionalidades que eles acabam com dois arquivos de configuração. E para criar os pacotes, você irá escrever os comandos no seu arquivo :

“scripts”: {
// npm run para gerar arquivos de produção
“build”: “webpack — config webpack.config.prod.js”,
// npm run vai gerar arquivos para dev e rodar o servidor
“dev”: “webpack-dev-server”
}

2. webpack CLI x webpack-dev-server

É importante tomar nota que o webpack, o empacotador, fornece duas interfaces:

  1. webpack CLI: A interface padrão (instalada como parte do próprio webpack)
  2. webpack-dev-server: Um pacote a parte que contém um servidor node.js

webpack CLI — Ótimo para produção

Essa interface recebe opções pela CLI e também pelo arquivo de configuração (padrão: webpack.config.js) e envia para o webpack processar.

Talvez você comece a aprender webpack pela CLI, no final, você só vai usá-la para gerar seus arquivos de produção.

Como usar:

OPÇÃO 1:// Instalando globalmente
$ npm install webpack — g
// Gera arquivos usando a configuração em webpack.config.js
$ webpack

OPÇÃO 2 :
// Instalando localmente e usando o package.json
$ npm install webpack — save
// Adicionando o comando ao package.json
“scripts”: {
“build”: “webpack — config webpack.config.prod.js -p”,
...
}
// Usando no terminal
$ npm run build

webpack-dev-server — Ótimo para desenvolvimento

Esse é um servidor Express usando rodando na porta . Esse servidor chama o webpack internamente. O benefício desse servidor, é que ele disponibiliza funcionalidades como: recarregar o navegador automáticamente (do inglês, ) e/ou substituir apenas o módulo que foi alterado (do inglês, ou ).

Como usar:

OPÇÃO 1:// Instalando globalmente
$ npm install webpack-dev-server -g
// Usando no terminal
$ webpack-dev-server --inline --hot

OPÇÃO 2:
// Instalando localmente e usando o package.json
$ npm install webpack-dev-server --save
// Adicionando o comando ao package.json
“scripts”: {
“start”: “webpack-dev-server --inline --hot”,
...
}
// Usando no terminal
$ npm start
// Abra o navegador em:
http://localhost:8080

webpack x webpack-dev-server e suas opções

É interessante saber que algumas opções como e estão disponíveis apenas no . E opções como são apenas da CLI.

webpack-dev-server opções da CLI x arquivo de configuração

Outra coisa que precisamos saber é que você pode passar opções para o webpack-dev-server de duas maneiras:

  1. Através do objeto no arquivo de configuração.
  2. Através de argumentos na CLI
// Via CLI
$ webpack-dev-server --hot --inline
// Via webpack.config.js
devServer: {
inline: true,
hot: true
}

Dica: Já percebi, algumas vezes, que as opções da chave (como e ) não funcionam! Então, eu prefiro passar elas diretamente na CLI no :

//package.json
{
scripts: {
“start”: “webpack-dev-server --hot --inline”
}
}

Atenção: Certifique-se de que você NÃO está passando e ao mesmo tempo.

webpack-dev-server — “hot” x “inline”

adiciona a opção de “recarregamento automático” (do inglês, ), para a página inteira. permite habilitar a opção (ou ), que tenta recarregar apenas o componente que foi modificado (ao invés da página inteira). Se passarmos as duas opções, então, quando o arquivo for modificado, tentará usar como primeira opção, se não funcionar, ele irá recarregar a página inteira.

// Quando o arquivo for modificado, as 3 opções seguintes são válidas// 1. Não recarrega a página automáticamente
$ webpack-dev-server
// 2. Recarrega a página automáticamente
$ webpack-dev-server --inline
// 3. Recarrega apenas o módulo (HMR) ou a página inteira caso falhe
$ webpack-dev-server --inline --hot

3. Chave “entry” — string x array x objeto

A chave fala para o webpack onde é a raíz de início do nosso módulo. Ela pode ser uma string, um array ou um objeto. Isso pode causar confusão, mas diferentes tipos significam diferentes resultados.

entry — String

Se você utilizar apenas um único ponto de início (como a maioria dos apps), você pode usar qualquer formato e o resultado será o mesmo.

Image for post
Image for post
Diferentes entradas, mas resultados iguais.

entry — Array

Mas, se você quiser concatenar múltiplos arquivos que NÃO DEPENDEM UM DO OUTRO, você pode usar um array como entrada.

Por exemplo: talvez você precise adicionar um no seu HTML. Você pode dizer para o webpack adicionar ele no final do seu arquivo bundle, dessa maneira:

Image for post
Image for post

entry — Object

Agora, vamos dizer que você tenha uma verdadeira aplicação com múltiplas páginas e módulos, não uma SPA com múltiplas rotas, mas com múltiplos arquivos HTML (como index.html, profile.html, cart.html). Você pode dizer ao webpack para gerar múltiplos arquivos bundle de uma só vez usando um objeto como entrada.

A configuração abaixo irá criar dois arquivos finais: e que você pode usar no index.html e profile.html respectivamente.

Image for post
Image for post

E então no HTML:

//profile.html
<script src=”dist/profileEntry.js”></script>
//index.html
<script src=”dist/indexEntry.js”></script>

Atenção: Perceba que o nome do arquivo vem da chave do objeto .

entry — Combinando ambos

Você também pode usar array como valor nas de entrada em objetos. No exemplo abaixo, a configuração irá gerar 3 arquivos: que contém três dependências, um e o .

Image for post
Image for post

4. Chave “ouput” — “path” x “publicPath”

A chave fala para o webpack onde e como ele deve armazenar os arquivos finais. Ele tem duas propriedades importantes, e , que podem gerar confusão.

A chave simplesmente diz ao webpack qual caminho ele deve usar para salvar os arquivos finais.

E o é usado por vários plugins do webpack para atualizar URLs dentro de arquivos CSS, HTML ou gerar arquivos para produção.

Image for post
Image for post
Chave publicPath em Dev x Prod

Por exemplo, no seu CSS, você pode ter uma url que carregue no seu localhost. Mas, em produção, esse pode estar armazenado em uma CDN, enquanto seu servidor node.js está rodando no Heroku. Isso quer dizer, que você teria que manualmente atualizar a URL em todos os arquivos e apontar para sua CDN quando enviar os arquivos para produção.

Ao invés disso, você pode usar a chave e alguns puglins que usam essa propriedade para automáticamente atualizar as URLs para produção.

Você pode clicar na imagem abaixo e ver alguns exemplos:

Image for post
Image for post
Exemplo da chave publicPath para Prod
// Dev: Servidor e imagem estão no seu localhost
.image {
background-image: url(./test.png);
}
// Prod: Servidor no Heroku e sua imagem na CDN
.image {
background-image: url(https://someCDN/test.png);
}

5. Usando e encadeando Loaders

é uma parte essencial do webpack, eles são módulos node que ajudam a carregar ou importar arquivos de vários tipos transformando-os em arquivos aceitáveis para o navegador, tais como JS, CSS e etc. E tudo isso através de arquivos JS usando (CommonJS) ou (ES6).

Por exemplo, você pode usar o babel-loader para converter JS escrito em ES6 para uma versão ES5 aceitável pela maioria dos navegadores:

module: {
loaders: [{
// Expressão regular procurando por arquivos
// que terminem em “.js”, se encontrar, use esse loader
test: /\.js$/,
// Exclui a pasta node_modules
exclude: /node_modules/,
// Você pode omitir o “-loader”, atalho para “babel-loader”
loader: ‘babel’
}]
}

Encadeando Loaders (da direita para esquerda)

Múltiplos podem ser encadeados para trabalhar em um mesmo arquivo. O encadeamento funciona da direita para esquerda e os são separados por .

Por exemplo, vamos supor que você tenha uma arquivo CSS chamado e você quer colocar seu conteúdo em uma tag dentro do seu arquivo HTML. Podemos conseguir isso usando dois loaders: e o .

module: {
loaders: [{
test: /\.css$/,
loader: 'style!css' // Atalho para style-loader!css-loader
}]
}

E ele funciona assim:

Image for post
Image for post
  1. webpack irá procurar por arquivos CSS que estejam sendo chamados pelo seus módulos. Ou seja, webpack irá examinar seu arquivo JS e procurar por . Se ele encontrar essa dependência, então, o webpack irá entregar esse arquivo para o primeiro loader, neste caso, o .
  2. irá carregar todo o arquivo CSS e suas dependências (caso ele tenha alguma declaração ) em formato JSON e enviar esse conteúdo para o .
  3. por sua vez, vai receber esse JSON e adicionar seu conteúdo a uma tag e injetar automáticamente no seu arquivo HTML.

6. Configurando seus Loaders

Seus podem funcionar de diferentes maneiras dependendo dos parâmetros que você passa.

Nos exemplos abaixo, nós estamos configurando o para transformar imagens menores de 1024 bytes em DataURLs e, manter as URLs normais para imagens maiores. Nós podemos fazer isso adicionando o parâmetro , que podemos configurar de duas maneiras:

Image for post
Image for post

7. O arquivo .babelrc

O usa algumas configurações pré-definidas em pacotes chamados . Alguma delas são os conhecidos presets para ES6/ES5 e também React/JSX. Nós podemos passar a configuração através de parâmetros:

module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: ‘babel’,
query: {
presets: [‘react’, ‘es2015’]
}
}
]
}

Porém, na maioria dos projetos que usam Babel, suas configurações e podem ficar bem grandes. Ao invés de manter tudo na configuração do , podemos mover essa configuração para o arquivo na raíz do seu projeto. irá carregar esse arquivo automaticamente se ele existir:

//webpack.config.js
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: ‘babel’
}
]
}
//.bablerc
{
“presets”: [“react”, “es2015”]
}

8. Plugins

Plugins são módulos node adicionais para transformar seu resultado final.

Por exemplo, recebe seu arquivo , minimiza e ofusca seu conteúdo, diminuindo o tamanho final.

Similarmente, , internamente usa o e para garantir que todo CSS final seja extraído em um arquivo separado e inclui o link no seu arquivo HTML.

//webpack.config.js//Procura todos os arquivos .css, combinando eles e extraindo para um único “styles.css”var ETP = require(“extract-text-webpack-plugin”);module: {
loaders: [
{
test: /\.css$/,
loader: ETP.extract("style-loader", "css-loader")
}
]
},
plugins: [
//Extrai todo CSS para "styles.css"
new ExtractTextPlugin("styles.css")
]

Nota: Se você quer injetar seu CSS inline no seu arquivo HTML, você pode fazer isso sem o , apenas usando e :

module: {
loaders: [{
test: /\.css$/,

// Você pode omitir o “-loader”,
// Atalho para style-loader/css-loader
loader: 'style!css'
}]
}

9. Loaders x Plugins

Se você chegou até aqui, acredito que tenha identificado duas coisas:

  1. Loaders: Trabalham exclusivamente nos arquivos durante ou antes do arquivo final () ser gerado.
  2. Plugins: Trabalham exclusivamente no arquivo final ou pedaços () e geralmente no final do processo de

Alguns plugins, como no caso do , vão além disso, e modificam como o .

10. Resolvendo extensões de arquivos

Várias configurações do webpack contêm um objeto de configuração chamado com uma propriedade que recebe uma vazia, como no exemplo abaixo. Essa vazia é importante porque ajuda a resolver caminhos de importação sem precisar saber a extensão do arquivo, tais como: ou .

{
resolve: {
extensions: [‘’, ‘.js’, ‘.jsx’]
}
}

E agora José?

Menos confuso? Eu espero que sim, fica minha recomendação para ler novamente cada tópico e tentar aplicar no seu dia-a-dia.

Apesar de sucinto as dicas, a documentação do webpack continua sendo um caos.

Obrigado Tobias Koppers (Criador do webpack) por revisar esse post!

Créditos

Meu muito obrigado! 🙏

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store