Webpack é complexo, mas só um pouquinho!

Posted by uselessdev on 01/04/2017

E ai povo, tudo bem?

Recentemente comecei a trabalhar com React (que aliás recomendo muito), fiz um curso na Alura e um no Egghead e os dois são cursos ótimos, nesses cursos foi apresentado uma ferramenta bastante interessante create-react-app que é muito útil quando você quer focar em aprender React ou quando você já domina.

Depois que finalizei os cursos senti falta de uma coisa aprender a configurar as tarefas de build pra conseguir rodar o React foi ai que eu me interessei pelo Webpack.

  • O que é Webpack
  • Configurando webpack
  • Lidando com módulos
  • Erros e Alertas
  • Um pouco de estilo
  • Notificações

O que é Webpack

Antes precisamos saber o que é Webpack.

Webpack é um empacotador de módulos ou (module bundler) em palavras mais simples: ele carrega seus módulos resolve as dependências do mesmo e concatena tudo em um único arquivo de uma maneira eficiente. Outras soluções como essa já existem há algum tempo como o RequireJS.

A diferença é que o Webpack não é restrito ao javascript, e você vai entender isso logo mais.

Configurando webpack

Vamos ao código, antes de iniciar é preciso que você tenha o webpack instalado globalmente, eu não tenho certeza se isso é um requisito ou não, porém eu tive alguns erros tentando rodar localmente, pra instalar globalmente:

1
npm i webpack -g

Feito isso vamos começar nossa estrutura de teste:

1
mkdir -p webpack/src webpack/src/components webpack/public webpack/public/js; touch webpack/public/index.html webpack/src/App.js webpack/src/components/Greet.js

Isso vai gerar a estrutura inicial pra começarmos a testar o webpack, agora vamos precisar instalarmos alguns módulos acesse a pasta webpack e rode:

1
npm init -y

Instalamos o webpack

1
npm i --save-dev webpack

E, agora vamos preparar nosso public/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Webpack</title>
</head>
<body>
<h1>Hello!</h1>
<!-- SCRIPTS -->
<script src="js/bundle.min.js"></script>
</body>
</html>

Lidando com módulos

Bem queremos é modularizar nosso código pra que ele não se torne muito complexo e repetitivo, então queremos fazer algo do tipo: var meuModulo = require('./meuModulo'), mas como sabemos nossos navegadores ainda não lidam muito bem com isso, é ai que entra os chamados module bundlers, vamos escrever nossos módulos: primeiro em src/components/Greet.js

1
2
3
4
5
function Greet (name) {
return 'Hello ' + name
}
module.exports = Greet

E src/App.js

1
2
3
var Greet = require('./components/Greet')
document.querySelector('h1').innerHTML = Greet('developer')

Agora precisamos fazer isso funcionar usando o webpack, primeiro vamos criar nosso arquivo de configuração webpack.config.js e adicionar o seguinte:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var env = process.env.NODE_ENV !== 'production'
var webpack = require('webpack')
module.exports = {
context: __dirname,
devtool: env ? 'inline-sourcemap' : false,
entry: './src/App.js',
output: {
path: __dirname + '/public/js',
filename: 'bundle.min.js'
},
plugins: env ? [] : [
new webpack.optimize.UglifyJsPlugin({
mangle: false,
sourcemap: false
})
]
}

Explicando sobre o arquivo:

  1. Context Onde nossa aplicação está rodando a pasta atual.
  2. devtool Definimos nosso ferramente de desenvolvedor verificando o ambiente env que nos diz se estamos em produção ou não.
  3. entry: O arquivo principal da nossa aplicação
  4. Output é um objeto que recebe informações de pra onde e como esse arquivo deve ser gerado: path é a pasta e filename o nome do arquivo
  5. plugins: Novamente verificamos o ambiente, aqui se estivermos em produção chamamos o plugin UglifyJS já definido no webpack pra minificar nosso arquivo final.

Agora vamos fazer um teste, no seu terminal execute o seguinte:

1
webpack

A saída no terminal vai ser algo como:

Webpack arquivo compilado

Se você olhar na sua pasta ./public/js o arquivo bundle.min.js vai tá lá também, porém não minificado, pra gerar ele minifcado basta rodar o webpack da seguinte forma:

1
NODE_ENV=production webpack

E o mesmo arquivo, minificado. A primeira parte já foi agora vamos avanção um pouquinho colocando o hot reloader assim não precisamos ficar rodando webpack toda vez que mudarmos nossos arquivos javascript.

Hot Reloader

Pra começar vamos adicionar o webpack-dev-server:

1
npm i --save-dev webpack-dev-server

E vamos configurar nosso webpack.config.js

1
2
3
4
5
6
7
entry: './src/App.js',
devServer: {
inline: true,
contentBase: './public',
publicPath: '/js',
port: 3000
},

Explicando até aqui:

  1. inline: Aqui dizemos que o webpack-dev-server vai inserir um runner no nosso código temporariamente pra poder rodar o servidor.
  2. contentBase: Aqui definimos a pasta que vai ser usada pelo servidor normalmente onde está nosso index.html.
  3. publicPath é onde vai ser gerado nosso arquivo final.
  4. port Nossa parta de acesso.

Adicionamos a opção devServer logo após o entry então agora basta rodarmos o seguinte comando:

1
node ./node_modules/.bin/webpack-dev-server

Se você excluir os arquivos gerados anteriormente, vai perceber que o webpack-dev-server não cria arquivo enquando ele roda, isso é bastante útil porque assim sua maquina não fica cheia de arquivos desnecessários.

Erros e Alertas

Até agora tudo bem, mas o webpack tem outra feature que me deixou bastante interessado.

Com o webpack-dev-server rodando, altere o nome do arquivo ./src/components/Greet.js pra qualquer coisa.

Se você abrir o devtools do navegador vai ver um erro no navegador, mas eu gostei bastante de uma feautre do create-react-app que literalmente joga esse erro pro navegador, ai pesquisando vi que na verdade isso é uma feature do webpack-dev-server e pra isso basta adicionarmos isso:

1
2
3
4
5
6
7
devServer: {
// ...
overlay: {
errors: true,
warnings: true
}
}

Rode novamente o webpack-dev-server

Você vai ver algo mais ou menos assim:

Webpack Erro

Bem mais simples perceber os erros né? Porém aqui ainda tem um probleminha, o webpack só dispara esses erros quando a compilação falha, como queremos ver outros erros vamos precisar de um outro módulo.

ESLINT

ESLint é uma ferramenta pra reforçar padrões no nosso código, normalmente a equipe define um padrão escreve essas configurações e todo o time passa a seguir o mesmo padrão e isso é ótimo, então vamos usar o módulo do eslint pra fazer isso pra gente junto com o webpack, assim ele vai realizar o lint no momento em que salvarmos nosso código.

Então primeiro vamos instalar nosso módulo:

1
npm i --save-dev eslint eslint-loader

Uma vez instalado vamos configurar nosso eslint pra rodar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
entry: './src/App.js',
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
failOnErrors: true,
failOnWarnings: true
}
}
]
},
devServer: {
// ...

Explicando o que fizemos aqui:

Adicionamos mais um indice ao nosso webpack.config.js e nele module, temos um array rules que possui um objeto, esse objeto é responsável pelo nosso loader de eslint:

  1. enforce: Aqui dizemos ao webpack pra executar isso no começo da compilação.
  2. test: Fazemos uma expressão regular pra acharmos todos os arquivos que terminan com .js
  3. exclude: Fazemos uma expressão pra encontrar node_modules e exclui-la do loader.
  4. loader: Nosso loader.
  5. options: As opções do nosso loader.

Se executarmos nosso webpack-dev-server ele vai dar um erro pois não encontrou a configuração do eslint pra isso vamos criar o arquivo .eslintrc.js e colocar o seguinte:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
env: {
browser: true,
commonjs: true,
es6: true,
node: true,
},
extends: 'eslint:recommended',
parserOptions: {
sourceType: 'module',
},
rules: {
'comma-dangle': ['error', 'always-multiline'],
indent: ['error', 2],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'no-unused-vars': ['warn'],
'no-console': 0
},
}

aqui é bem simples, primeiro definos os ambientes usados, logo depois extendemos alguma pré configuração, no nosso caso o recomendado, depois definimos algumas opções de parser e por fim nossa configuração.

Agora rode o webpack-dev-server no seu navegador você vai ser algo mais ou menos assim:

Webpack Lint

Há algum tempo atrás eu adotei o StandardJS em meus projetos por ser mais conciso e por ser um padrão pré definido que não suporta mudanças em suas configurações de code guide se você também quer usa-lo com ESlint basta seguir os passos abaixo:

  1. Instalando os módulos:
1
npm i --save-dev eslint-config-standard eslint-plugin-promise eslint-config-standard
  1. Configurando nosso .eslintrc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
env: {
browser: true,
commonjs: true,
es6: true,
node: true,
},
extends: 'standard',
parserOptions: {
sourceType: 'module',
},
rules: {}
}

Como você percebeu nós removemos todas as regras e trocamos o extends pra standard, rodando o webpack-dev-server de novo, alguns erros como semicolon vão aparecer no seu navegador:

Webpack Erro

Um pouco de estilo?

Bom até aqui nós só vimos sobre Javascript , porém também queremos um pouco de css e claro, podemos usar o webpack pra lidar com nossos estilos também lembram que eu escrevi lá em cima que ele não era exclusivo pra javascript, vamos começar com um pouco de css, então instalando nossas dependências:

1
npm i --save-dev css-loader style-loader

E vamos configurar nosso webpack.config.js:

1
2
3
4
5
6
7
8
rules: {
...
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
...
}

Bem agora vamos criar nosso arquivo src/Styles/greet.css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body { height: 100%; }
body {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #ecf0f1;
}
h1 {
color: #34495e;
font: 3rem/1.5 Arial;
}

Agora lá no src/App.js:

1
2
3
...
require('./Styles/greet.css')
...

E pronto, seu css está funcionando maravilhosamente, porém, eu não costumo utilizar css puro, normalmente eu uso o pré processador Stylus então, vamos configurar ele no nosso webpack também:

1
yarn add -D stylus stylus-loader

Agora basta trocarmos nosso src/Styles/greet.css por src/Styles/greet.styl e mudarmos nossa sintaxe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*
margin 0
padding 0
box-sizing border-box
body
width 100%
height 100vh
display flex
align-items center
justify-content center
background #ecf0f1
h1
color #34495e
font 3rem/1.5 Arial

E claro no nosso src/App.js:

1
require('./Styles/greet.styl')

Feito isso vamos ao avançar um pouco mais, que tal tentarmos um Hello World com ES6?

ES6

Vamos configurar nosso webpack.config.js pra lidar com ES6 por padrão o webpack apenas compila nosso ES5 se quisermos usar o ES6 precisamos de uma ferramenta pra realizar esse transpiler e pra isso vamos trabalhar com Babel, então instalando nossas dependências:

1
npm i --save-dev babel-core babel-loader babel-preset-es2015

Agora configuramos nosso webpack.config.js lá em rules adicione o seguinte:

1
2
3
4
5
6
7
8
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}

Agora vamos mudar nosso src/components/Greet.js

1
2
const Greet = name => `Hello ${name}`
export default Greet

E nosso src/App.js

1
2
3
4
5
6
import Greet from './components/Greet'
import './Styles/greet.styl'
const User = 'developer'
document.querySelector('h1').innerHTML = Greet(User)

E pronto, é isso.

Temos agora um module bundler efetivo e confgurado com webpack! É claro que o webpack não se limita apenas isso, e você não só pode como deve recorrer a documentaçao oficial da ferramenta. Bem por enquanto é isso e até mais galera.


Comentários: