Variáveis de Ambiente
Ao executar o webpack, é possível definir variáveis de ambiente através da linha de comando para personalizar a compilação. Por exemplo, para configurar um ambiente local de produção com barra de progresso:
npx webpack --env.ambiente=local --env.producao --progresso
Tree Shaking
O Tree Shaking remove código JavaScript não utiilzado do bundle final. Esta técnica funciona apenas com módulos ES6 que utilizam import e export. Para habilitá-lo, configure a opção de otimização:
otimizacao: {
exportacoesUtilizadas: true
}
No arquivo package.json, é necessário indicar efeitos colaterais para arquivos que não devem ser analisados, como folhas de estilo:
"efeitosColaterais": ["*.css", "*.scss"]
Ambientes de Desenvolvimento e Produção
Utilize o pacote webpack-merge para criar configurações distintas para desenvolivmento e produção. O ambiente de desenvolvimento requer hot reloading, source maps detalhados e um servidor local. Em produção, busca-se bundles minificados e source maps leves.
Code Splitting (Divisão de Código)
A divisão de código pode ser realizada de duas maneiras principais. Primeiramente, definindo múltiplos pontos de entrada:
entrada: {
principal: caminho.resolve(__dirname, '../src/index.js'),
utilitarioLodash: caminho.resolve(__dirname, '../src/lodash.js')
}
No arquivo lodash.js, exporte a biblioteca para o escopo global:
import _ from 'lodash';
window._ = _;
Em segundo lugar, utilize a configuração optimization.splitChunks para extrair código comum de módulos síncronos:
otimizacao: {
divisaoDeChunks: {
blocos: 'todos'
}
}
Para código assíncrono, basta utilizar a importação dinâmica, que será dividida automaticamente:
async function obterLodash() {
const { default: _ } = await import(/* webpackNomeDoChunk: 'lodash' */ 'lodash');
const elemento = document.createElement('div');
elemento.innerHTML = _.join(['Olá', 'Mundo'], '-');
return elemento;
}
obterLodash().then(resultado => {
document.body.appendChild(resultado);
});
Análise de Bundle
Para analisar o conteúdo do bundle, gere um arquivo de estatísticas e utilize ferramentas como webpack-bundle-analyzer ou sites de análise:
npx webpack --perfil --json > estatisticas.json
Nomes de Arquivo e Chunks
A opção output.filename controla os nomes dos arquivos gerados a partir dos pontos de entrada. A opção output.chunkFilename é usada para chunks não listados na entrada, como aqueles carregados dinamicamente via import().
Carregamento Assíncrono de Código
Utilize importações dinâmicas para carregar código sob demanda, melhorando o desempenho inicial da página ao reduzir o tamanho do bundle principal.
Prefetching e Preloading
Para carregar recursos de forma antecipada durante o tempo ocioso da rede, use os comentários mágicos webpackPrefetch ou webpackPreload:
document.addEventListener('click', function () {
import(/* webpackPrefetch: true */ './moduloClique').then(({ default: funcao }) => {
funcao();
});
});
Extração de CSS com MiniCssExtractPlugin
O plugin mini-css-extract-plugin extrai CSS para arquivos separados. A configuração básica inclui definição de nomes de arquivo:
const ExtrairCss = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new ExtrairCss({
nomeArquivo: '[nome].css',
nomeArquivoChunk: '[id].css',
}),
],
modulo: {
regras: [
{
teste: /\.css$/,
uso: [
ExtrairCss.loader,
'css-loader',
],
},
],
},
};
Em desenvolvimento, habilitar o hot module replacement (HMR) para CSS:
const ExtrairCss = require('mini-css-extract-plugin');
const emDesenvolvimento = process.env.NODE_ENV !== 'production';
module.exports = {
plugins: [
new ExtrairCss({
nomeArquivo: emDesenvolvimento ? '[nome].css' : '[nome].[hash].css',
nomeArquivoChunk: emDesenvolvimento ? '[id].css' : '[id].[hash].css',
}),
],
modulo: {
regras: [
{
teste: /\.(sa|sc|c)ss$/,
uso: [
{
loader: ExtrairCss.loader,
opcoes: {
hmr: process.env.NODE_ENV === 'development',
},
},
'css-loader',
'postcss-loader',
'sass-loader',
],
},
],
},
};
Em produção, minificar o CSS utilizando plugins como optimize-css-assets-webpack-plugin:
const TerserJSPlugin = require('terser-webpack-plugin');
const ExtrairCss = require('mini-css-extract-plugin');
const OtimizarCSS = require('optimize-css-assets-webpack-plugin');
module.exports = {
otimizacao: {
minimizador: [new TerserJSPlugin({}), new OtimizarCSS({})],
},
plugins: [
new ExtrairCss({
nomeArquivo: '[nome].css',
nomeArquivoChunk: '[id].css',
}),
],
modulo: {
regras: [
{
teste: /\.css$/,
uso: [ExtrairCss.loader, 'css-loader'],
},
],
},
};
Cache com contenthash
Para invalidação eficiente de cache, utilize contenthash nos nomes dos arquivos. O formato é:
[<tipoHash>:contenthash:<tipoResumo>:<comprimento>]
Shimming (Adaptação de Módulos)
O plugin ProvidePlugin injeta variáveis automaticamente, eliminando a necessidade de importações explícitas em cada arquivo:
const webpack = require('webpack');
// ... dentro da configuração de plugins
new webpack.ProvidePlugin({
_: 'lodash'
})
No código-fonte, a variável _ pode ser usada sem importação direta:
const elemento = document.createElement('div');
elemento.innerHTML = _.join(['Bem-vindo', 'Usuário'], ' ');
document.body.appendChild(elemento);
O imports-loader pode alterar o contexto de this em módulos, por exemplo, para apontar para o objeto window:
uso: 'imports-loader?this=>window'
Integração com TypeScript
Para compilar TypeScript, utilize ts-loader e configure o tsconfig.json:
modulo: {
regras: [
{
teste: /\.tsx?$/,
exclusao: /node_modules/,
uso: [
{
loader: 'ts-loader'
}
]
}
]
}
Arquivo tsconfig.json de exemplo:
{
"opcoesDoCompilador": {
"diretorioSaida": "./dist",
"modulo": "es6",
"alvo": "es5",
"permitirJs": true
}
}
Código TypeScript de exemplo:
import * as _ from 'lodash';
class Saudacao {
mensagem: string;
constructor(msg: string) {
this.mensagem = msg;
}
cumprimentar() {
console.log(_.join([this.mensagem, 'Programador'], '_'));
}
}
const saudacao = new Saudacao('Olá');
saudacao.cumprimentar();
Configuração do DevServer
O servidor de desenvolvimento suporta opções como historyApiFallback para rotas de aplicação de página única, proxy para redirecionar requisições e secure para conexões HTTPS.
Resolução de Módulos com resolve
Use resolve.alias para criar atalhos a diretórios frequentemente acessados:
module.exports = {
//...
resolver: {
alias: {
Utilitarios: caminho.resolve(__dirname, 'src/utilitarios/'),
Modelos: caminho.resolve(__dirname, 'src/modelos/')
}
}
};
Defina extensões de arquivo preferidas com resolve.extensions:
module.exports = {
//...
resolver: {
extensoes: ['.wasm', '.mjs', '.js', '.json']
}
};