No post anterior vimos uma introdução ao Webpack, criamos uma situação básica carregando múltiplos arquivos JavaScript e vimos que Webpack possui 4 elementos chaves: Entry(arquivo de entrada), output(arquivo de saída), loaders e plugins. Nesse tutorial vamos abordar como trabalhamos como loaders, Webpack em seu core nada mais é que JavaScript carregando JavaScript. Nada mais básico que em uma aplicação web termos uma série de assets com diferentes extensões, jpg, css, js, svg… e como o Webpack se trata com essa situações, a resposta é: Loaders

Loaders

Loaders dão Webpack a possibilidade de processar diferentes tipos de arquivos, define como o Webpack irá ler e exportar os assets do seu projeto. Escritos em Node.JS os loaders precisam regras escritas em expressão regular para definir quais extensões serão carregadas pelo tal.

Temos vários loaders e podemos separa-los nas seguintes categorias:

  • Arquivos
  • JSON
  • Transpiling
  • Templating
  • Styling
  • Linting
  • Frameworks

Para nosso tutorial vamos utilizar os seguintes recursos, babel para fazer o transpiling do nosso ECMAScript2015+ e JSX e Sass para fazer o pre-processamento do nosso estilo. Com esse panorama vamos precisar dos seguintes loaders:

  • Arquivos: url-loader, file-loader
  • Transpiling: babel-loader
  • Styling: style-loader, css-loader, sass-loader

Com essa lista vamos seguir um passo-a-passo e falar sobre cada um desses loaders durante a evolução de nosso projeto.

babel-loader

Hoje desenvolvimento com JavaScript moderno é um requisito quase que obrigatório em projetos web, em nossos exemplos anteriores fizemos o uso de EcmaScript 5, versão suportada por todos os browsers do mercado incluindo internet Explorer, mas se a gente quiser fazer o uso de EcmaScript2015+ e não deixar de fora os usuários de browsers mais antigos, reposta será “transpiling”, ele funciona como uma compilação de código, onde temos EcmaScript 2015+ sendo convertido para EcmaScript 5, no mercado temos algumas ferramentas que realizam esse processo atualmente a ferramenta mais usada no mercado é babel.

Webpack é umas da tecnologias compatíveis com babel, assim podemos fazer o processo de transpiling utilizando babel para criar o nosso bundle. Para isso vamos primeiramente instalar babel-loader em nosso projeto, dentro do nosso terminal, na pasta do seu projeto executamos o seguinte comando:

npm install -D babel-loader @babel/core @babel/preset-env

Nesse código temos a instalação do babel-loader, babel core e preset-env, presets são coleções de plugins para o babel suportar uma certa versão, ainda temos presets para cada versão do EcmaScript, react e typescript. Mas a preset-env tem o foco no target environment, ou seja, no ambiente final. Ele suporta as versões mas recentes do ecmaScript, mas o código gerado conseguimos determinar qual será o nível de suporte. Após a instalação dos pacotes nosso package.json ficará da seguinte forma:

{
  "name": "webpack-tutorial",
  "version": "1.0.0",
  "description": "Webpack tutorial",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/fellyph/webpack-tutorial.git"
  },
  "keywords": [
    "tutorial",
    "webpack"
  ],
  "author": "fellyph",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/fellyph/webpack-tutorial/issues"
  },
  "homepage": "https://github.com/fellyph/webpack-tutorial#readme",
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "babel-loader": "^8.0.5",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  },
  "dependencies": {
    "npm": "^6.7.0"
  }
}

Depois de instalado os pacotes necessários, vamos incluir o loader em nosso webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};

No código acima adicionamos um novo atributo chamado module, ele será responsável por definir as regras de como os nosso módulos serão carregados, passamos um array de regras(rules) contendo os seguintes parâmetros:

  • test: contém uma expressão regular para achar os arquivos que iremos aplicar a regra, na sua maioria utilizamos a extensão que buscamos.
  • exclude: também uma expressão regular, contendo os arquivos ou pastas que iremos ignorar.
  • use: qual o loader iremos utilizar para esse caso.

Por exemplo, em nosso código definimos que todos arquivos que terminam com a extensão .js iremos usar o loader ‘babel-loader‘, dentro do nosso código de entrada adicionamos EcmaScript2015 se conferimos o código gerado temos, por exemplo, a keyword ‘const’ convertida para ‘var’. O exemplo completo você pode conferir na branch step-6.

style-loader e css-loader

Continuando a evolução de nosso webpack.config.js vamos carregar o nosso estilo, para essa tarefa vamos instalar dois loaders css-loader e style-loader, css-loader vai ser responsável por carregar o css junto com webpack e style-loader vai pegar o conteúdo carregado pelo webpack e exportá-lo em uma tag style. Agora em nosso terminal iremos rodar o seguinte código:

npm i -D style-loader css-loader

Completa a instalação vamos adicionar o loader em nosso webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.css$/,
        exclude: /(node_modules|bower_components)/,
        use: ['style-loader', 'css-loader'],
      }
    ]
  }
};

Após adicionarmos a configuração para carregar nosso css o padrão será o mesmo, regex para achar os arquivos css, quais o loaders iremos utilizar com a propriedade use, adicionei um css simples chamado main.css:

:root {
  --c-text:#28262C;
  --c-component-background: #F9F5FF;
  --c-primary: #14248A;
  --c-secondary: #D4C2FC;
  --c-ternary: #998FC7;
  --e-padding: 1em;
}

.navigation,
.main,
.header,
.footer {
  padding: var(--e-padding);
}

.navigation {
  background: var(--c-primary);
}

.main {
  background: var(--c-component-background);
}

.header {
  background: var(--c-component-background);
}

.footer {
  background: var(--c-ternary);
}

Em nosso index.js vamos carregar o css, isso mesmo, faremos o import dentro do nosso arquivo de entrada:

import './css/main.css';

import './js/content';
import './js/header';
import './js/footer';

Quando executarmos o comando webpack em nossa linha de comando teremos a seguinte saída, o arquivo gerado o main.js e os arquivos que serviram de entrada para nosso bundle. O código para esse loader você irá encontrar na branch step-7

Vamos adicionar uma image ao nosso projeto via css, a imagem abaixo será a imagem que iremos trabalhar voce pode salva-la e adicionar na pasta assets/imgs/

Com a image no local definido vamos fazer a seguinte alteracao em nosso CSS:

:root {
  --c-text:#28262C;
  --c-component-background: #F9F5FF;
  --c-primary: #14248A;
  --c-secondary: #D4C2FC;
  --c-ternary: #998FC7;
  --e-padding: 1em;
  --header-img: url(../../assets/imgs/webpack-logo.png);
}

.navigation,
.main,
.header,
.footer {
  padding: var(--e-padding);
}

.navigation {
  background: var(--c-primary);
}

.main {
  background: var(--c-component-background);
}

.header {
  background: var(--header-img);
  background-repeat: no-repeat;
}

.footer {
  background: var(--c-ternary);
}

Vamos adicionar a nossa imagem como background do nosso header e tentar compilar o nosso código:

Temos um erro de compilacao do nosso codigo

Isso acontece porque não temos o loader apropriado para a extensão .png, para esse caso podemos trabalhar com loaders:

  • file-loader: irá carregar o arquivo e criar uma copia do arquivo em nossa pasta de output(dist)
  • url-loader: irá carregar o arquivo especificado e irá criar uma copia no formato base64.

Para corrigir o nosso projeto iremos instalar dos dois loaders:

npm i -D file-loader url-loader

Com os loaders instalados vamos combinar os dois loaders em uma solução, arquivos pequenos convertemos em base64 e arquivos pesado criamos uma copia em nossa pasta dist, como podemos ver em nosso webpack.config.js (step-8):

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.css$/,
        exclude: /(node_modules|bower_components)/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(svg|gif|png|jpe?g)$/,
        loader: 'url-loader',
        options: {
          limit: 100,
          fallback: 'file-loader',
          publicPath: '/img',
          outputPath: '/img',
        },
      },
    ]
  }
};

Agora temos loaders para nossos arquivos .js .css e images, caso queiramos trabalhar com pre-processadores, por exemplo, SASS ou LESS, parra o nosso tutorial iremos trabalhar com SASS mas o processo é similar para o LESS. Primeiro em nosso terminal iremos instalar os pacotes necessários:

npm install sass-loader node-sass --save-dev

Com tudo pronto vamos alterar a regra de leitura no nosso css para também aceitar arquivos SASS.

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.(sa|sc|c)ss$/,
        exclude: /(node_modules|bower_components)/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.(svg|gif|png|jpe?g)$/,
        loader: 'url-loader',
        options: {
          limit: 100,
          fallback: 'file-loader',
          publicPath: '/img',
          outputPath: '/img',
        },
      },
    ]
  }
};

A principal diferença em nosso webpack.config.js é regex que anteriomente procurava arquivos com a extensão .css agora com a regra ‘(sa|sc|c)ss’ procura arquivos .sass .scss ou .css e por fim adicionamento o sass-loader, se trocarmos a extensão do nosso arquivo .css por .scss ele irá carregar normalmente. Exemplo:

_variables.scss

$c-text:#28262C;
$c-component-background: #F9F5FF;
$c-primary: #14248A;
$c-secondary: #D4C2FC;
$c-ternary: #998FC7;
$e-padding: 1em;
$header-img: url(../../assets/imgs/webpack-logo.png);

main.scss

@import 'variables';

.navigation,
.main,
.header,
.footer {
  padding: $e-padding;
}

.navigation {
  background: $c-primary;
}

.main {
  background: $c-component-background;
}

.header {
  background: $header-img;
  background-repeat: no-repeat;
}

.footer {
  background: $c-ternary;
}

O código completo desse tutorial você irá encontrar na branch step-9 E até o próximo tutorial.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *