Module Bundler

Webpack

Webpack é o module bundler testado em batalha. Ele transforma um grafo de módulos, assets e dependências em bundles otimizados — e entendê-lo torna qualquer outra ferramenta de build mais clara.

advanced14 min readUpdated 15 de set. de 2026
webpack.config.js
js
// webpack.config.js
import path from "node:path";

export default {
  entry: "./src/index.js",
  output: {
    path: path.resolve(import.meta.dirname, "dist"),
    filename: "[name].[contenthash].js",
    clean: true,
  },
  module: {
    rules: [
      { test: /\.css$/, use: ["style-loader", "css-loader"] },
    ],
  },
  optimization: { splitChunks: { chunks: "all" } },
};
Primeiro lançamento
2012
Modelo
Grafo de dependências
Transformações
Loaders
Extensões
Plugins
Dev server
webpack-dev-server
Ainda usado por
Muitos apps enterprise

Por que importa

Por que o Webpack ainda é importante

Lida com tudo

JavaScript, CSS, imagens, fontes e muito mais fluem por um único pipeline, tornando o grafo completo e explícito.

Profundamente configurável

Loaders, plugins e opções de otimização permitem moldar o build com precisão quando os padrões não são suficientes.

Otimização poderosa

Code splitting, tree shaking, caching e minificação estão todos disponíveis, com controle granular.

O panorama completo

As três ideias por trás do Webpack

Um grafo de dependências, loaders que transformam arquivos e plugins que estendem o build.

O grafo

Descobrir

Partindo dos entry points, o Webpack segue os imports para construir um grafo de cada módulo e asset.

Loaders

Transformar

Funções que transformam um arquivo em um módulo, como compilar TypeScript ou processar CSS.

Plugins

Estender

Integram-se ao ciclo de vida do build para tarefas que vão além da transformação de arquivos individuais.

Webpack em resumo

O núcleo do Webpack

Entry

Os módulos iniciais a partir dos quais o Webpack constrói o grafo de dependências.

Output

Onde os bundles são gravados e como são nomeados, incluindo content hashes.

Loaders

Transformam arquivos antes de entrarem no grafo, como o babel-loader ou css-loader.

Plugins

Estendem o build com geração de HTML, variáveis de ambiente e mais.

Code splitting

Dynamic import e splitChunks criam bundles separados carregados sob demanda.

Tree shaking

Remove exports não utilizados, o que requer ES modules e código livre de side-effects.

Uma breve historia

O bundler que construiu a web moderna

  1. 2012

    Lançamento do Webpack

    Tobias Koppers apresenta um bundler que trata cada asset como um módulo.

    12
  2. 2014

    Webpack 1

    O bundler torna-se popular com a ascensão do React e de single-page apps.

    14
  3. 2016

    Webpack 2

    Chegam os ES modules nativos e o tree shaking.

    16
  4. 2020

    Webpack 5

    Lançamento de persistent caching, module federation e asset modules.

    20
  5. Hoje

    Ainda em produção

    Vite é o padrão moderno, mas o Webpack continua amplamente difundido em apps existentes.

    Hoje

O guia completo

Webpack: Tudo que voce precisa saber

O que é Webpack?

Webpack é um module bundler. A partir de um ou mais pontos de entrada (entry points), ele segue cada importação e constrói um grafo dos módulos e assets da sua aplicação. Em seguida, ele os transforma e combina em um pequeno número de bundles que o navegador consegue carregar de forma eficiente.

Lançado em 2012, o Webpack tornou-se a espinha dorsal do build front-end moderno. O Vite é agora o padrão para novos projetos por ser mais rápido e simples, mas o Webpack ainda sustenta um número enorme de aplicações em produção, e seus conceitos — o grafo de dependências, loaders, plugins e code splitting — são o vocabulário de todo bundler que veio depois.

Entrada e saída

As duas configurações obrigatórias são onde o grafo começa e para onde os bundles vão.

// webpack.config.js
import path from "node:path";

export default {
  entry: "./src/index.js",
  output: {
    path: path.resolve(import.meta.dirname, "dist"),
    filename: "[name].[contenthash].js",
    clean: true,
  },
};

entry é o módulo inicial. output.filename utiliza um hash de conteúdo para que os navegadores possam fazer o cache dos bundles permanentemente e baixar novamente apenas os que foram alterados. clean: true remove arquivos obsoletos antes de cada build.

Loaders

Por padrão, o Webpack entende apenas JavaScript. Os Loaders transformam outros arquivos em módulos conforme eles entram no grafo.

// loaders.js
export default {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: "ts-loader",
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|svg|woff2)$/,
        type: "asset",
      },
    ],
  },
};

Uma regra possui um test para definir quais arquivos ela deve corresponder e um use para o loader ou loaders a serem aplicados. Os loaders são executados da direita para a esquerda, portanto, ["style-loader", "css-loader"] primeiro analisa o CSS e depois o injeta na página. O Webpack 5 também possui asset modules, que substituem os antigos file-loader e url-loader para imagens e fontes.

Plugins

Plugins estendem o próprio processo de build. Enquanto um loader transforma um arquivo, um plugin se conecta ao ciclo de vida da compilação.

// plugins.js
import HtmlWebpackPlugin from "html-webpack-plugin";
import { DefinePlugin } from "webpack";

export default {
  plugins: [
    new HtmlWebpackPlugin({ template: "./src/index.html" }),
    new DefinePlugin({
      "process.env.NODE_ENV": JSON.stringify("production"),
    }),
  ],
};

Plugins comuns geram o arquivo HTML, definem variáveis de ambiente, copiam assets estáticos, analisam o tamanho do bundle e limpam a saída. É aqui que reside a maior parte do poder — e a maior parte da complexidade — do Webpack.

Resolve e aliases

As opções de resolve controlam como as importações são encontradas.

// resolve.js
export default {
  resolve: {
    extensions: [".ts", ".tsx", ".js"],
    alias: {
      "@": path.resolve(import.meta.dirname, "src"),
    },
  },
};

O extensions permite que você importe arquivos sem especificar a extensão, e o alias cria atalhos para que as importações não fiquem repletas de caminhos ../../... Geralmente, o mesmo alias é espelhado na configuração do TypeScript para que o editor esteja em sincronia com o bundler.

Code splitting e tree shaking

Duas otimizações dominam a performance em produção.

O Code splitting divide o bundle em chunks carregados sob demanda. O import() dinâmico é a ferramenta principal, e o splitChunks extrai automaticamente as dependências compartilhadas.

// split.js
export default {
  optimization: {
    splitChunks: { chunks: "all" },
  },
};

O Tree shaking remove exports não utilizados, mas apenas quando consegue analisar os imports estaticamente. Isso significa utilizar ES modules (import/export) em vez de CommonJS, e módulos que sejam livres de side effects. Marcar pacotes como sideEffects: false em seu package.json permite que o Webpack faça a poda (pruning) de forma agressiva.

O servidor de desenvolvimento

webpack-dev-server serve o build em desenvolvimento com hot module replacement.

// devServer.js
export default {
  devServer: {
    port: 3000,
    hot: true,
    historyApiFallback: true,
    proxy: [{ context: ["/api"], target: "http://localhost:8787" }],
  },
};

historyApiFallback faz com que o roteamento no client-side funcione ao servir index.html para caminhos desconhecidos, e proxy encaminha as requisições de API para o seu backend. O servidor de desenvolvimento mantém o build em memória, tornando os rebuilds rápidos.

Quando usar Webpack

O Webpack ainda é uma escolha sólida quando você mantém uma aplicação existente, depende de um loader ou plugin específico, ou precisa de recursos avançados como module federation para micro-frontends. Sua configuração é verbosa, mas também é extremamente capaz e previsível assim que você a compreende.

Para novos projetos, o Vite geralmente é a melhor escolha padrão: inicialização mais rápida, configuração mais simples e uma API de plugins moderna. Aprender Webpack ainda vale a pena porque seus conceitos são transferíveis — a interface de plugins do Vite é compatível com Rollup e as mesmas ideias de grafo, transforms e splitting se aplicam em qualquer lugar.

Melhores práticas

  • Mantenha a configuração dividida em arquivos ou funções de common, dev e prod.
  • Use hashes de conteúdo nos nomes dos arquivos para cache de longo prazo.
  • Prefira ES modules para que o tree shaking funcione.
  • Divida funcionalidades pesadas com dynamic imports.
  • Marque pacotes sem efeitos colaterais (side-effect-free) para que o código não utilizado seja removido.
  • Espelhe resolve.alias na configuração do TypeScript.
  • Analise o bundle com um visualizador quando ele crescer inesperadamente.

Erros comuns

  • Enviar tudo em um único bundle e nunca fazer code splitting.
  • Usar CommonJS e se perguntar por que o tree shaking não funciona.
  • Colocar um loader na ordem errada e receber erros confusos.
  • Duplicar a configuração entre ambientes em vez de compô-la.
  • Criar aliases no Webpack, mas não no TypeScript, fazendo com que o editor aponte erros.
  • Adicionar um plugin que duplica uma funcionalidade nativa do Webpack 5.

Próximos passos

O Webpack é a base histórica das ferramentas de build modernas e continua sendo uma escolha confiável para aplicações existentes. Compare-o com o Vite para novos projetos, entenda os pacotes npm que fornecem loaders e plugins, e veja como as mesmas ideias aparecem no Turborepo para builds de monorepos. Depois, leia a configuração do Webpack do seu projeto e rastreie um arquivo desde a entrada (entry) até a saída (output).

Habilitando tree shaking

Tree shaking precisa de sintaxe ES module. Chamadas require do CommonJS são dinâmicas demais para que exports não utilizados sejam removidos com segurança.

Preferir
// math.js
export function add(a, b) {
  return a + b;
}
export function unused() {}

// only add is bundled
Evitar
// math.js
module.exports = {
  add: (a, b) => a + b,
  unused: () => {},
};
// both shipped to the browser

Dividindo código

Dynamic import cria um chunk separado carregado apenas quando necessário. Imports estáticos colocam tudo no bundle inicial.

Preferir
async function openEditor() {
  const { Editor } = await import(
    "./Editor"
  );
  return Editor;
}
Evitar
import { Editor } from "./Editor";
// heavy editor in the
// initial bundle for everyone

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Webpack?

Nosso tutorial interativo te guia por Webpack passo a passo — com quizzes e codigo real que voce pode executar no navegador.