Na natureza dinâmica do JavaScript moderno, é essencial lembrar que “antigo” não significa necessariamente “desatualizado”, e “novo” nem sempre implica “melhor”.

O segredo para escolher a tecnologia certa está no alinhamento dela com as necessidades do seu projeto. Esse princípio faz todo o sentido quando se consideram os empacotadores de módulos JavaScript. Independentemente de um empacotador ter resistido ao teste do tempo ou ter sido introduzido recentemente, cada um deles apresenta vantagens e limitações distintas.

Este artigo explora duas ferramentas importantes e populares: Vite e Webpack. Avaliamos esses empacotadores com base em seus recursos, distinções, filosofias arquitetônicas e como eles se integram ao ecossistema do desenvolvedor.

O que é um empacotador de módulos JavaScript?

Empacotador Javascript.
Empacotador Javascript.

Um empacotador (bundler) JavaScript é uma ferramenta usada no desenvolvimento web para combinar vários arquivos JavaScript em um único arquivo, conhecido como pacote. Ele simplifica o gerenciamento do código JavaScript, reduzindo o número de solicitações que o aplicativo web precisa fazer, o que, em última análise, melhora o desempenho.

Por exemplo, considere dois arquivos JavaScript separados: module1.js e module2.js. O module1.js contém o seguinte conteúdo:

// module1.js
export const greet = (name) => {
    console.log(`Hello, ${name}!`);
}

E o module2.js contém:

// module2.js
export const farewell = (name) => {
    console.log(`Goodbye, ${name}!`);
}

Para empacotar esses módulos em um único arquivo, você pode usar um empacotador como Rollup, Webpack ou Parcel. Por exemplo, se você criar um arquivo index.js no diretório do seu projeto com o código abaixo:

// index.js
import { greet } from './module1.js';
import { farewell } from './module2.js';

greet('Kinsta');
farewell('Server Troubles');

Ao utilizar um empacotador JavaScript, ele combina module1.js, module2.js e index.js em um único pacote otimizado e adaptado para o uso do seu aplicativo web.

Embora os navegadores web modernos ofereçam suporte a módulos ES e tecnologias como HTTP/2, que lidam com questões de sobrecarga de solicitações, os empacotadores JavaScript continuam sendo indispensáveis para uma série de aprimoramentos no código. Eles realizam transformações essenciais no código, incluindo minificação, transpilação e otimização.

Além disso, os empacotadores de módulos JavaScript garantem a compatibilidade entre vários navegadores. Eles ajudam a resolver problemas específicos de navegadores e garantem uma experiência consistente para os usuários, independentemente do navegador web escolhido.

Esse processo de empacotamento não apenas acelera a velocidade de carregamento do seu aplicativo web, mas também garante um desempenho eficiente, principalmente em ambientes de produção. Agora que você entende os empacotadores de JavaScript e sua função no desenvolvimento web, vamos focar no Vite e no Webpack.

Vite e Webpack: Introdução e Visão Geral

É evidente que o Vite e o Webpack lideram o campo em rápido crescimento do desenvolvimento web moderno, em que o gerenciamento de recursos e pacotes otimizados são vitais. Mas antes de nos aprofundarmos em uma comparação detalhada, vamos dar uma olhada rápida nesses empacotadores e entender no que se destacam.

Vite: desenvolvimento ágil e sob demanda

O Vite é um divisor de águas para desenvolvedores web, priorizando velocidade e eficiência. O que faz o Vite se destacar é sua abordagem de empacotamento sob demanda. Em vez de empacotar previamente todos os códigos e ativos, o Vite aproveita os módulos ES nativos dos navegadores modernos, fornecendo o código diretamente ao navegador durante o desenvolvimento. Isso leva à substituição quase instantânea do Hot Module Replacement (HMR) e à redução dos tempos de cold start.

O servidor de desenvolvimento do Vite se destaca com essa abordagem sob demanda, permitindo que os desenvolvedores vejam as alterações rapidamente sem recompilação completa. Ele também usa o Rollup, para builds de produção eficientes. Como resultado, o Vite oferece um desenvolvimento extremamente rápido e um sólido desempenho de produção.

Webpack: organizado e adaptável

O Webpack é a pedra angular do desenvolvimento web moderno, evoluindo constantemente desde 2012. O que é ótimo no Webpack é como ele organiza os componentes do site. Ele otimiza tempos de carregamento e a experiência do usuário ao organizar o código em módulos.

A adaptabilidade do Webpack é uma vantagem significativa. Os desenvolvedores podem personalizar projetos para tarefas simples ou complexas. Ele permite que os desenvolvedores personalizem fluxos de trabalho e criem processos com precisão.

Semelhanças e diferenças entre o Vite e o Webpack

Agora que já entendemos os conceitos básicos do Vite e do Webpack, vamos explorar suas semelhanças e diferenças com mais detalhes. À medida que analisamos esses empacotadores, examinamos vários aspectos para obter uma compreensão abrangente de como eles se comparam e onde cada um se destaca.

1. Arquitetura e filosofia

Ambos os empacotadores oferecem perspectivas exclusivas sobre a criação e a otimização de aplicativos web. Eles compartilham sua abordagem de plugins, permitindo que a comunidade crie plugins adicionais úteis que estendem suas funcionalidades, tornando-os ferramentas versáteis para desenvolvedores.

A filosofia central do Vite gira em torno da simplicidade e extensibilidade. Ele adere a uma estratégia minimalista, concentrando-se nos padrões mais comuns de desenvolvimento de aplicativos web prontos para uso. Essa abordagem garante a manutenção do projeto a longo prazo.

A confiança do Vite em um sistema de plugins baseado em rollup evita o inchaço do núcleo, permitindo a implementação de recursos por meio de plugins externos. Isso promove um núcleo simplificado e incentiva um ecossistema próspero de plugins bem mantidos. Além disso, o Vite colabora ativamente com o projeto Rollup para manter a compatibilidade e um ecossistema de plugins compartilhado.

O Webpack capacita os desenvolvedores com personalização, permitindo que eles adaptem os projetos a necessidades específicas, desde tarefas básicas até empreendimentos complexos. Ele oferece flexibilidade na configuração de todos os aspectos do processo de build, tornando-se a opção ideal para quem busca uma experiência de desenvolvimento personalizada.

Além disso, o Webpack introduz a abordagem modular, semelhante a uma montagem de blocos de Lego para projetos web. Tudo em sua base de código é um módulo para o Webpack, e ele pode expressar suas dependências de várias maneiras. Alguns exemplos são:

  1. Declaração ES2015 import.
  2. Declaração CommonJS require().
  3. Declarações AMD define e require.
  4. Declaração @import dentro de um arquivo css/sass/less.
  5. URL da imagem em um arquivo de folha de estilo url() ou HTML <img src="">.

A filosofia do Vite em ação

A filosofia arquitetônica do Vite, de ser enxuta e extensível, é evidente em sua abordagem da criação de aplicativos web. Suponha que você esteja desenvolvendo um aplicativo web e queira incluir recursos modernos de JavaScript, como módulos ES. Com o Vite você pode fazer isso sem esforço. Aqui está um exemplo simplificado:

// app.js
import { greet } from './utilities.js';

const worker = new Worker(new URL('./worker.js', import.meta.url));

// Simulate a calculation in the web worker
worker.postMessage({ input: 42 });

worker.onmessage = (e) => {
  const result = e.data.result;
  console.log(`Result from the web worker: ${result}`);
};

const message = greet('Hello, Vite!');
console.log(message);

Nesse snippet de código, o Vite adota o uso de módulos ES e empacota o código sem esforço em tempo real, evitando etapas demoradas de empacotamento durante o desenvolvimento. Essa abordagem modular permite que você gerencie dependências de forma eficiente, criando uma base de código sustentável. Isso demonstra o compromisso do Vite com o minimalismo e experiências amigáveis para o desenvolvedor.

A filosofia do Webpack em ação

A filosofia modular do Webpack é particularmente benéfica no trabalho em projetos de grande escala. Imagine que você está criando um aplicativo web substancial com vários módulos JavaScript. Com o Webpack, você pode montar esses módulos sem dificuldades, melhorando a legibilidade, a manutenção e o tempo de carregamento do site. Aqui está um exemplo simplificado:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      },
    ],
  },
};

Neste exemplo, o Webpack permite que você configure o processo de build, otimize o código e manipule os ativos com eficiência. Organizando seu projeto em módulos e usando carregadores como o Babel, você pode escrever um código limpo e modular que melhora a experiência do usuário. Isso demonstra o compromisso do Webpack em fornecer personalização e flexibilidade, garantindo que os desenvolvedores possam adaptar seus projetos a necessidades específicas.

Embora o Vite e o Webpack tenham filosofias arquitetônicas distintas, eles compartilham o compromisso de ampliar os limites do moderno desenvolvimento para a web. O Vite se concentra em padrões de codificação modernos, promovendo os Módulos ECMAScript (ESM) para código-fonte e incentivando padrões modernos, como a nova sintaxe do Worker para web workers.

O Webpack, por outro lado, evoluiu como uma resposta aos desafios apresentados pelo Node.js e pelo CommonJS, impulsionando a adoção de módulos no desenvolvimento web. A coleta automática de dependências do Webpack, aliada a melhorias de desempenho, garante uma experiência perfeita para o desenvolvedor.

2. Popularidade, comunidade e ecossistema

O Vite e o Webpack têm cronogramas distintos, que moldam sua popularidade e comunidade.

Comparação entre o Vite e o Webpack no Google Trends nos últimos 5 anos.
Comparação entre o Vite e o Webpack no Google Trends nos últimos 5 anos.

O Vite é um recém-chegado, tendo estreado em 2020. Apesar de sua existência relativamente curta, o Vite tem ganhado atenção rapidamente, tornando-se um participante promissor no campo do desenvolvimento web moderno.

Por outro lado, o Webpack teve uma vantagem significativa. Tendo sido criado em 2012, seu tempo no setor permitiu que desenvolvesse um ecossistema maduro e uma comunidade robusta.

Vite e o Webpack comparados nos últimos 5 anos no npmtrends.
Vite e o Webpack comparados nos últimos 5 anos no npmtrends.

O gráfico acima, do npmtrends, ilustra a comparação da contagem de downloads entre o Vite e o Webpack. Ele mostra claramente que o Webpack mantém consistentemente uma posição de destaque em termos de contagem de downloads, enfatizando sua presença de longa data e a extensão de seu uso na comunidade de desenvolvedores.

Comparação entre o Vite e o Webpack no star-history.
Comparação entre o Vite e o Webpack no star-history.

Quando analisamos as estrelas do GitHub usando o star-history, que é uma medida de popularidade e suporte da comunidade, descobrimos que o Vite possui impressionantes 60.318 estrelas, enquanto o Webpack mantém uma forte presença com 63.598 estrelas. Essas contagens refletem o reconhecimento e o envolvimento ativo em ambos os projetos. O rápido crescimento do Vite e a popularidade sustentada do Webpack fazem deles ativos valiosos no cenário de desenvolvimento web.

3. Configuração e facilidade de uso

Tanto o Vite quanto o Webpack oferecem várias opções de configuração para você adaptar o pacote de acordo com suas necessidades específicas. No entanto, há diferenças significativas que merecem atenção. Vamos explorar a configuração e a facilidade de uso das duas ferramentas.

Configuração simplificada do Vite

O Vite se diferencia por sua filosofia de configuração zero, projetada para simplificar sua jornada de desenvolvimento web. Isso significa que você pode criar uma biblioteca básica de componentes Vue 3 com o mínimo de esforço. Aqui está uma configuração simples do Vite para um projeto desse tipo:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
})

No exemplo acima, somente importamos e instalamos o plugin oficial do Vite para Vue.js. A mágica do Vite está em sua capacidade de detectar automaticamente as configurações corretas para a maioria dos projetos.

Complexidade de configuração do Webpack

O Webpack, por outro lado, tende a exigir uma configuração mais detalhada. Embora tenha se movido em direção a uma abordagem de configuração zero em versões recentes, ele não é tão automático quanto o Vite. Para o Vue 3, uma configuração básica do Webpack pode ser assim:

const webpack = require('webpack');
const path = require('path');
const { HotModuleReplacementPlugin } = require('webpack');
const { VueLoaderPlugin } = require('vue-loader');

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

Comparada ao Vite, a configuração do Webpack envolve mais ajustes manuais. As complexidades incluem a especificação de caminhos de entrada e saída, configuração de carregadores para diferentes tipos de arquivos e a definição de plugins para funcionalidades específicas. Vamos detalhar cada parte da configuração e apontar as complexidades:

  • Entrada e saída: entry especifica o ponto de entrada do seu aplicativo, onde o Webpack iniciará o empacotamento. Nesse caso, ele é definido como ./src/main.js, supondo que o arquivo JavaScript principal do seu aplicativo esteja no diretório src, enquanto output define onde os arquivos empacotados devem ser salvos. O caminho de saída é resolvido usando path.resolve, e o arquivo do pacote resultante é denominado bundle.js e salvo no diretório build.
  • Regras de módulo: A seção module.rules define como os diferentes tipos de arquivos são processados. Nesse caso, há regras para arquivos JavaScript (babel-loader para transpilação), componentes de arquivo único do Vue (vue-loader) e arquivos CSS (vue-style-loader e css-loader para manipulação de estilos).
  • Configuração de aliases: A seção resolve.alias define aliases para importações de módulos. Neste caso, está configurando um alias do Vue para vue/dist/vue.js.
  • Plugins: A seção de plugins inclui HotModuleReplacementPlugin, que habilita a substituição de módulos a quente, um recurso que permite ver as alterações sem recarregar a página inteira durante o desenvolvimento, enquanto VueLoaderPlugin é necessário para o processamento de componentes de arquivo único do Vue.

Para resumir esta seção, o Vite se destaca em termos de facilidade de uso, oferecendo uma configuração simplificada e uma experiência de desenvolvimento otimizada. Seus requisitos mínimos de configuração e o uso de módulos ES nativos o tornam excelente para iniciantes e para o desenvolvimento rápido.

Em contrapartida, a extensa configurabilidade do Webpack, embora benéfica para projetos complexos, pode representar um desafio para desenvolvedores iniciantes. A configuração e a manutenção complexas podem retardar o desenvolvimento, especialmente em projetos menores.

4. Servidor de desenvolvimento

O servidor de desenvolvimento desempenha uma função crucial no fluxo de trabalho do desenvolvedor, influenciando a eficiência e a produtividade. Vamos comparar o Vite e o Webpack, avaliando o desempenho e a usabilidade do servidor de desenvolvimento para descobrir qual é a melhor ferramenta para o seu projeto de desenvolvimento web.

Configuração do servidor

O Vite se destaca por seu servidor de desenvolvimento integrado e pronto para uso, muitas vezes eliminando a necessidade de configuração extensiva.

Em contrapartida, o Webpack oferece flexibilidade, mas requer configuração adicional. Os desenvolvedores podem escolher opções como o Watch Mode do Webpack, webpack-dev-server e webpack-dev-middleware para compilação automática de código após alterações. No entanto, geralmente é necessário configuração para estabelecer e ajustar detalhes dessas opções.

Velocidade de cold start

As configurações tradicionais baseadas em empacotadores envolvem rastreamento ansioso e exigem a criação de todo o aplicativo antes de servir, o que leva a atrasos perceptíveis, principalmente em projetos complexos.

O Vite revoluciona os cold starts com uma abordagem fundamentalmente diferente, reduzindo drasticamente o tempo de inicialização:

Tempo no Esbuild para criar um pacote de produção de 10 cópias da biblioteca three.js a partir do zero usando as configurações padrão.
Tempo no Esbuild para criar um pacote de produção de 10 cópias da biblioteca three.js a partir do zero usando as configurações padrão. (Fonte da imagem: Esbuild)
  • Tratamento eficiente de dependências: O Vite utiliza o esbuild, um empacotador de alto desempenho baseado em Go, para pré-empacotar dependências, incluindo JavaScript simples e módulos grandes. Tudo isso contribui significativamente para uma inicialização mais rápida do servidor. Como parte do processo de empacotamento prévio, o Vite otimiza o desempenho mesclando dependências ESM com vários módulos internos em um único módulo. Por exemplo, o lodash-es contém mais de 600 módulos internos. Usando métodos tradicionais, ao importar uma função como debounce são acionadas mais de 600 solicitações HTTP. A solução do Vite é pré-empacotar o lodash-es em um único módulo, reduzindo as solicitações HTTP a apenas uma. Essa redução drástica nas solicitações aumenta significativamente a velocidade de carregamento da página no servidor de desenvolvimento.

    Gráfico do servidor de desenvolvimento baseado em ESM.
    Gráfico do servidor de desenvolvimento baseado em ESM. (Fonte da imagem: Vite)

  • Carregamento de código-fonte sob demanda: O Vite utiliza módulos ES nativos para servir o código-fonte, minimizando a carga e a latência do servidor. A transformação e a veiculação do código-fonte ocorrem mediante solicitações do navegador, aumentando a eficiência e reduzindo os tempos de espera.

    Gráfico do servidor de desenvolvimento baseado em pacotes.
    Gráfico do servidor de desenvolvimento baseado em pacotes. (Fonte da imagem: Vite)

O Webpack, por outro lado, adota uma abordagem baseada em pacotes, empacotando previamente o código-fonte e as dependências, estendendo os tempos de início do servidor durante o desenvolvimento. Em comparação com a inicialização eficiente do Vite, o tempo de configuração do servidor do Webpack é inerentemente mais longo.

No entanto, a abordagem de carregamento sob demanda do Vite pode introduzir um pequeno atraso quando os usuários navegam para rotas que exigem dados, CSS e ativos adicionais. Isso é particularmente perceptível se esses recursos exigirem outras etapas de empacotamento. Por outro lado, a estratégia do Webpack garante que todos os dados do site estejam disponíveis, levando a uma navegação mais rápida para novas páginas dentro do servidor de desenvolvimento.

HMR (Hot Module Replacement, substituição de módulo quente)

O Vite utiliza o HMR em vez do ESM nativo, reduzindo a carga e a latência do servidor ao transferir parte do trabalho de empacotamento para o navegador. Isso garante atualizações rápidas sem o recarregamento da página inteira, o que é crucial para o feedback em tempo real durante o desenvolvimento.

O Webpack também oferece suporte ao HMR, permitindo atualizações em tempo real e preservando o estado do aplicativo durante o desenvolvimento. No entanto, as possíveis limitações na utilização de módulos ES nativos podem levar a uma maior carga e latência do servidor.

Desempenho do armazenamento em cache

O armazenamento em cache é essencial para melhorar o desempenho dos aplicativos web, reduzindo a carga e os tempos de build com a reutilização de ativos armazenados.

O armazenamento em cache no Vite é gerenciado com um cache de sistema de arquivos, atualizando as dependências com base nas alterações em package.json, lockfiles e vite.config.js. Ele otimiza as recargas de página armazenando em cache as solicitações de dependências resolvidas.

O Webpack também usa cache de sistema de arquivos, limpando os arquivos modificados no modo de observação e limpando o cache antes de cada compilação no modo sem observação, exigindo configuração personalizada para otimizar o cache.

Para finalizar a comparação do servidor de desenvolvimento, o Vite e o Webpack oferecem abordagens distintas:

  • O Vite fornece um servidor de desenvolvimento pronto para uso, minimizando o excesso de configurações.
  • O Webpack oferece flexibilidade de configuração, mas exige ajustes adicionais.
  • O Vite é excelente em velocidade de cold start e HMR para alterações rápidas de código.
  • O Webpack tem melhor desempenho na velocidade de navegação devido a dados do site empacotados previamente.
  • Ambos são compatíveis com HMR, mas têm mecanismos diferentes de servir os módulos.
  • O Vite gerencia o cache local e do navegador sem problemas, ao passo que o Webpack precisa de configuração personalizada.

5. Tempo de build e tamanho de pacote

Agora vamos comparar o tempo de build e o tamanho de pacote entre o Vite e o Webpack, considerando o build de desenvolvimento, a mudança quente durante o servidor de desenvolvimento e o build de produção.

Nosso ambiente de teste envolve:

  • Executar testes no MacBook Air com um chip Apple M1 e GPU de 8 núcleos.
  • Um projeto Vue 3 de escala média com 10 componentes, utilizando o Vuex para gerenciamento de estado e o Vue Router para roteamento.
  • Incorporação de folhas de estilo (CSS/SASS) e ativos como imagens e fontes, juntamente com um número moderado de dependências.

Vamos começar comparando o tempo de empacotamento:

Vite [v4.4.11] Webpack [v5.89.0]
Primeiro build de desenvolvimento 376 ms 6 s
Mudança quente Instantânea 1.5 s
Build de produção 2 s 11 s

O Vite surge como o claro vencedor em velocidade de empacotamento, reduzindo drasticamente os tempos de build. Embora o Webpack ofereça configurabilidade e ferramentas de desenvolvimento robustas, ele sofre um atraso em relação ao Vite.

Vite [v4.4.11] (KB) Webpack [v5.89.0] (KB)
Tamanho do pacote de produção 866 kb 934 kb

Esses números são baseados em um aplicativo Vue.js de tamanho médio com um número moderado de dependências. O tamanho real do pacote pode variar dependendo da complexidade do projeto, das dependências e das técnicas de otimização.

O tamanho reduzido do pacote do Vite se deve ao seu pré-empacotamento eficiente com o esbuild e os módulos ES nativos.

O tamanho do pacote do Webpack pode ser otimizado por meio de várias opções de configuração e plugins, mas ele geralmente produz pacotes maiores devido ao seu processo abrangente de empacotamento.

6. Otimização do build

Quando se trata de otimizar o processo de build no moderno desenvolvimento web, o Vite e o Webpack oferecem abordagens distintas, cada uma com seu próprio conjunto de recursos e capacidades. Vamos nos aprofundar na otimização do build, explorando as principais diferenças entre o Vite e o Webpack.

Geração de diretivas de pré-carregamento

O Vite gera automaticamente as diretivas <link rel="modulepreload"> para blocos de entrada e suas importações diretas no HTML criado. Isso melhora os tempos de carregamento ao pré-carregar os módulos de forma eficiente, conforme necessário.

Portanto, ao inspecionar a página, você pode encontrar algo semelhante a isto:

<!-- Vite - Module Preloading -->
<link rel="modulepreload" href="/module-a.js">

O Webpack não suportava nativamente as dicas do navegador para recursos. Mas a partir do Webpack v4.6.0, ele incluiu suporte para pré-busca e pré-carregamento. O uso de uma diretiva inline ao declarar importações permite que o Webpack emita uma dica de recurso, que fornece ao navegador informações sobre quando carregar o arquivo importado. Por exemplo:

import(/* webpackPreload: true */ '/module-a.js');

Você verá isso na saída:

<!-- Webpack - Manual Module Preloading -->
<link rel="preload" as="script" href="/module-a.js">

Divisão de código CSS

O Vite se destaca por sua abordagem simplificada da divisão de código CSS. Ele extrai automaticamente o CSS usado pelos módulos em blocos assíncronos e gera arquivos separados. Isso significa que somente o CSS necessário é carregado por meio de uma tag <link> quando o bloco assíncrono associado é carregado.

Em especial, o Vite garante que o bloco assíncrono seja avaliado somente depois que o CSS for carregado, evitando o Flash of Unstyled Content (FOUC). Como esse recurso é pré-configurado, você pode continuar importando seus arquivos CSS sem nenhuma etapa adicional:

import './main.css';

O Webpack oferece flexibilidade, mas exige mais configuração para a divisão do código CSS. Ele permite que os desenvolvedores dividam o CSS usando vários plugins e opções de configuração, como mini-css-extract-plugin.

// Webpack - CSS Code Splitting
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

Divisão de código e carregamento de blocos

A divisão de código é uma técnica fundamental usada para dividir seu código em partes menores e mais gerenciáveis, carregando apenas o que é necessário exatamente quando necessário. Essa prática reduz significativamente os tempos de carregamento inicial e preserva recursos.

Abordagem do Vite para blocos

Há casos em que o Vite usa o Rollup para dividir o código em blocos separados automaticamente, como carregamento dinâmico ou múltiplos pontos de entrada, e há uma maneira de dizer explicitamente ao Rollup quais módulos devem ser divididos em blocos separados por meio da opção output.manualChunks.

Além do recurso pré-configurado de divisão de código, o Vite também oferece suporte a importações dinâmicas com variáveis:

const module = await import(`./dir/${kinsta}.js`)

O Vite também permite que os desenvolvedores dividam blocos de fornecedores usando o plugin oficial splitVendorChunkPlugin():

import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
  plugins: [splitVendorChunkPlugin()],
})

Com todas essas importações dinâmicas e divisões de código, é comum que o código seja estruturado em módulos ou blocos, e alguns desses módulos são compartilhados entre diferentes partes de um aplicativo web. O Vite reconhece blocos comuns e otimiza o processo de carregamento. Para entender melhor, vamos dar uma olhada no exemplo da documentação oficial do Vite.

Gráfico exibindo o bloco comum necessário em dois blocos assíncronos.
Gráfico exibindo o bloco comum necessário em dois blocos assíncronos. (Fonte da imagem: Vite)

Sem a otimização, quando um usuário abre uma seção de um aplicativo web — vamos chamá-la de Seção A — que depende do código compartilhado Common Chunk C, o navegador começa buscando a Seção A. Ao analisar a Seção A, ele percebe que precisa do Common Chunk C. Isso requer uma viagem de ida e volta adicional pela rede, o que pode tornar o carregamento inicial da página mais lento:

Entry (Section A) ---> async chunk A ---> common chunk C

O Vite, por outro lado, emprega um recurso sofisticado chamado Async Chunk Loading Optimization. Ele não espera que o navegador descubra suas necessidades; em vez disso, ele se prepara proativamente para elas. Quando um usuário solicita a Seção A, o Vite envia a Seção A e o Common Chunk C simultaneamente. Essa busca paralela dos blocos necessários acelera significativamente o processo de carregamento:

Entry (Section A) ---> (async chunk A + common chunk C)

Mas não para por aí. O Common Chunk C pode ter suas próprias dependências, o que poderia causar mais viagens de ida e volta em um cenário não otimizado. O Vite não ignora esse aspecto. Ele analisa rigorosamente essas dependências, garantindo que tudo o que é necessário, independentemente de sua profundidade, seja carregado de uma só vez com eficiência. Isso elimina a necessidade de viagens adicionais de ida e volta pela rede, garantindo um aplicativo web altamente responsivo.

A abordagem de carregamento de blocos assíncronos do Vite otimiza o processo de carregamento, buscando e servindo proativamente todos os blocos de código necessários em paralelo. Essa eliminação de viagens extras de ida e volta à rede resulta em uma experiência mais ágil na web. É como fornecer um itinerário de viagem bem preparado ao seu navegador, garantindo que ele receba todos os recursos necessários sem atrasos evitáveis.

Abordagem do Webpack da divisão de código

Quanto ao Webpack, há três técnicas gerais disponíveis para a divisão de código:

  1. Pontos de entrada: Essa é a maneira mais fácil de dividir um pedaço do código. Podemos simplesmente definir um novo ponto de entrada no arquivo de configuração e o Webpack o adicionará como um bloco separado:
    const path = require('path');
     module.exports = {
      mode: 'development',
      entry: {
        index: './src/index.js',
        another: './src/separate-module.js',
      },
       output: {
        filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
     };

    No entanto, essa abordagem tem limitações. Se os módulos forem importados em pedaços de entrada diferentes, eles acabarão em ambos os pacotes, levando a um código duplicado. Além disso, ela não é muito adaptável para dividir a lógica do aplicativo principal quando necessário.

  2. Evitar duplicação: Outra abordagem é usar as dependências entry ou SplitChunksPlugin. Aqui está um exemplo de como configurar a divisão de código usando dependências entry:
    const path = require('path');
    
     module.exports = {
       mode: 'development',
       entry: {
         index: {
           import: './src/index.js',
           dependOn: 'shared',
         },
         another: {
           import: './src/another-module.js',
           dependOn: 'shared',
         },
         shared: 'lodash',
       },
       output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist'),
       },
      optimization: {
        runtimeChunk: 'single',
      },
     };
  3. Importações dinâmicas: Por fim, o Webpack oferece suporte a importações dinâmicas, um recurso valioso para o carregamento de código sob demanda. Ele usa a sintaxe em conformidade com a proposta ECMAScript para importações dinâmicas. Esse método é mais flexível e granular, tornando-o adequado para vários cenários de divisão de código.
    const { default: _ } = await import('lodash');

    Também podemos usar os Magic Comments do Webpack para definir um nome para o bloco, fazer lazy-load, especificar exportações de módulo e definir uma prioridade de busca:

    import(
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackExports: ["default", "named"] */
      /* webpackFetchPriority: "high" */
      'module'
    );

Tree-Shaking

O tree-shaking (sacudir a árvore) é uma técnica de otimização crucial que o Vite e o Webpack usam para reduzir o tamanho dos pacotes de JavaScript.

O Vite utiliza o Rollup, que não apenas permite o uso de módulos ES, mas também analisa estaticamente o código que você importa. Isso significa que o Vite pode excluir qualquer parte de um módulo que você não use, resultando em pacotes menores. Por exemplo, se você tiver um módulo com várias funções, mas usar apenas uma delas, o Vite incluirá apenas essa função no pacote. Aqui está um exemplo simples:

  • Sem usar módulos ES, se você quiser importar ajax de ./utils.js, precisará importar o arquivo inteiro.
    const utils = require('./utils');
    const query = 'Kinsta';
    // Use the 'ajax' method of the 'utils' object
    utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
  • O uso de módulos ES, por outro lado, permite que você importe apenas o que precisa, resultando em bibliotecas e aplicativos mais leves, rápidos e menos complexos. Como o Vite usa declarações explícitas import e export, ele pode executar um tree-shaking altamente eficaz sem depender exclusivamente de um minificador automatizado para detectar código não utilizado.
    import { ajax } from './utils';
    const query = 'Kinsta';
    // Call the 'ajax' function
    ajax(`https://api.example.com?search=${query}`).then(handleResponse);

Por fim, com o Vite, podemos usar opções pré-configuradas do Rollup para tree-shaking.

O Webpack também oferece suporte ao tree-shaking, mas tem um mecanismo diferente. Ele analisa as dependências em seu código e remove as partes não utilizadas durante o processo de empacotamento. Embora seja eficaz, ele pode não ser tão completo quanto a abordagem do Vite, principalmente ao lidar com grandes módulos ou bibliotecas.

Além disso, de acordo com a documentação do Webpack, precisamos marcar os arquivos como livres de efeitos colaterais para garantir que ele não removerá nenhum código que tenha outro código em produção que dependa dele.

A maneira como isso é realizado é por meio da propriedade sideEffects do package.json:

{
  "name": "kinsta-app",
  "sideEffects": false
}

Vale a pena observar que uma opção de configuração semelhante para definir efeitos colaterais também existe nas opções de Rollup do Vite.

7. Tratamento de ativos estáticos

Ativos estáticos, como imagens, fontes e outros arquivos, são parte integrante do desenvolvimento web. O Vite e o Webpack abordam o manuseio desses recursos de forma diferente, cada um com seus próprios pontos fortes e otimizações.

Manuseio de ativos do Vite

A abordagem do Vite para manejar ativos estáticos é simplificada e eficiente. Quando você importa um ativo estático, o Vite retorna a URL pública resolvida quando ele é servido. Por exemplo, quando você importa uma imagem como esta:

import kinstaImage from './kinsta-image.png';

Durante o desenvolvimento, imgUrl será resolvida para /img.png. No build de produção, ela se tornará algo como /assets/img.2d8efhg.png, otimizada para armazenamento em cache e desempenho.

O Vite pode lidar com essas importações com caminhos públicos absolutos ou relativos, tornando-o flexível para as necessidades do seu projeto. Esse comportamento se estende a referências de URL em CSS, que o Vite trata sem problemas.

Além disso, se você estiver usando o Vite em um componente de arquivo único (SFC) do Vue, as referências de ativos nos modelos serão automaticamente convertidas em importações, simplificando o seu fluxo de trabalho de desenvolvimento.

O tratamento de ativos do Vite vai ainda mais longe, detectando tipos comuns de arquivos de imagem, mídia e fonte, que são tratados como ativos. Esses ativos são incluídos como parte do gráfico de ativos do build, recebem nomes de arquivos com hash e podem ser processados por plugins para otimização.

Tratamento de ativos do Webpack

O Webpack, por sua vez, tem uma abordagem diferente para o tratamento de ativos estáticos. Com o Webpack, você importa ativos como faz normalmente:

import kinstaImage from './kinsta-image.png';

O Webpack processa essa importação adicionando a imagem ao seu diretório de saída e fornecendo a você a URL final da imagem. Isso facilita o trabalho com ativos e também funciona dentro do seu CSS usando url('./my-image.png'). O css-loader do Webpack reconhece isso como um arquivo local e substitui o caminho pela URL final da imagem no diretório de saída. O mesmo se aplica ao usar o html-loader para <img src="./kinsta-image.png" />.

Os Módulos de Ativos do Webpack introduzidos na versão 5 podem manipular vários tipos de ativos, não apenas imagens. Por exemplo, você pode configurar o Webpack para lidar com arquivos de fonte:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        type: 'asset/resource',
      },
    ],
  },
};

Essa configuração permite que você incorpore fontes em seu projeto por meio de uma declaração @font-face.

8. Suporte a sites estáticos

Sites estáticos oferecem inúmeras vantagens, como tempos de carregamento rápidos, segurança aprimorada e hospedagem simplificada. Um site estático é composto de HTML, CSS e JavaScript, o que proporciona uma experiência de usuário simplificada e entrega eficiente de conteúdo. Tanto o Vite quanto o Webpack podem ajudar os desenvolvedores a gerar sites estáticos de alto desempenho, mas não com a mesma eficiência.

Abordagem do Vite para a geração de sites estáticos

O Vite oferece instruções dedicadas para a implantação de sites estáticos, capitalizando sua abordagem simplificada de desenvolvimento e implantação, particularmente adequada para sites estáticos.

Outro aspecto interessante do Vite é que ele tem um script preview, que ajuda os desenvolvedores a iniciar localmente seu build de produção para ver o resultado final do aplicativo em ação. Esse recurso permite que os desenvolvedores testem e visualizem seu build de produção antes de implantá-lo em um servidor ativo.

No entanto, é importante observar que o script preview do Vite destina-se a visualizar o build localmente e não para funcionar como um servidor de produção. Isso significa que ele é uma ótima ferramenta para os desenvolvedores testarem seus aplicativos antes da implantação, mas não é adequado para hospedar um site de produção ao vivo.

{
  "scripts": {
    "preview": "vite preview --port 3000"
  }
}

Vale a pena destacar o VitePress, uma das ferramentas mais poderosas do ecossistema Vite. O VitePress é um gerador de site estático (SSG) para gerar sites rápidos e focados em conteúdo. O VitePress pega seu texto de origem baseado em Markdown, aplica um tema e gera páginas HTML estáticas que podem ser rapidamente implantadas gratuitamente na Kinsta.

Abordagem do Webpack para geração de sites estáticos

Embora o Webpack não tenha sido projetado especificamente para a geração de sites estáticos, ele pode ser usado para criar sites estáticos por meio de vários plugins e configurações. No entanto, o processo é geralmente mais complexo e menos simplificado em comparação com o Vite. O foco principal do Webpack está no empacotamento e na otimização de módulos JavaScript, o que o torna uma ferramenta poderosa para a criação de aplicativos web complexos.

9. Suporte à renderização do lado do servidor

A renderização do lado do servidor (SSR) é uma técnica de desenvolvimento web que renderiza páginas web no servidor e envia o HTML totalmente renderizado para o navegador do cliente. Vamos comparar os dois pacotes em termos de suporte a SSR:

  • Vite: O Vite oferece suporte à renderização no lado do servidor, oferecendo uma abordagem simplificada para aplicativos que exigem SSR. Com o Vite, as estruturas de frontend que podem executar o mesmo aplicativo no Node.js, pré-renderizá-lo em HTML e, posteriormente, hidratá-lo no lado do cliente podem ser perfeitamente integradas. Isso torna o Vite uma excelente opção para aplicativos que exigem recursos de SSR, fornecendo aos desenvolvedores as ferramentas necessárias para otimizar seus aplicativos renderizados no servidor.
  • Webpack: O Webpack também pode ser usado para renderização no lado do servidor. No entanto, a implementação da SSR com o Webpack tende a ser mais complexa e requer um conhecimento mais profundo de configuração e instalação. Os desenvolvedores talvez precisem investir mais tempo na configuração do SSR com o Webpack em comparação com a abordagem mais simplificada oferecida pelo Vite.

10. Suporte a JSON

Tanto o Vite quanto o Webpack suportam a importação de arquivos JSON. Exceto que, no Vite, as importações nomeadas de JSON também são suportadas para ajudar com o tree-shaking.

// import an object
import json from './example.json'
// import a root field as named exports.
import { test } from './example.json'

11. Suporte a Vue.js e JSX

O Vue.js, um importante framework JavaScript, segue a sintaxe SFC (Single File Component), simplificando o processo de criação de interfaces de usuário. Em contraste, o JSX é uma extensão da sintaxe JavaScript, usada principalmente no React, que permite aos desenvolvedores definir estruturas de interface de usuário usando tags e elementos semelhantes a HTML.

O Vite oferece suporte de primeira classe ao Vue.js com plugins oficiais que integram perfeitamente o Vite ao Vue. Ele também lida com arquivos JSX (.jsx e .tsx) imediatamente, graças à transpilação do esbuild. Os usuários do Vue.js podem utilizar o plugin @vitejs/plugin-vue-jsx, adaptado para o Vue 3, que oferece recursos como HMR, resolução global de componentes, diretivas e slots.

Nos casos em que o JSX é usado com outros frameworks, como React ou Preact, o Vite permite a configuração de jsxFactory e jsxFragment personalizados por meio da opção esbuild. Esse nível de flexibilidade é valioso para projetos que exigem personalização do JSX.

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
  },
})

Por outro lado, o Webpack não oferece suporte nativo ao Vue.js ou a quaisquer outras bibliotecas, ou frameworks específicos. Os desenvolvedores precisam instalar carregadores e dependências relevantes para configurar um projeto para um framework JavaScript moderno, o que torna o processo mais manual e potencialmente complexo.

12. Suporte a TypeScript

O Vite oferece suporte nativo ao TypeScript, permitindo a incorporação perfeita de arquivos .ts nos projetos. Ele usa o transpilador esbuild para uma transformação rápida do código durante o desenvolvimento. O foco do Vite é a transpilação, não a verificação de tipos. Ele espera que o seu IDE e o processo de build lidem com a verificação de tipos.

O Webpack não tem suporte nativo ao TypeScript, portanto, os desenvolvedores precisam configurar manualmente o TypeScript usando o compilador typescript e o ts-loader. Isso requer a configuração do tsconfig.json para especificar as opções do TypeScript. Depois de configurado, o Webpack usa o ts-loader para compilar o código TypeScript. Embora isso introduza etapas de configuração adicionais, oferece flexibilidade e compatibilidade com outros recursos do Webpack.

13. Suporte ao Glob Import

O Vite oferece suporte ao Glob Import. Esse recurso é usado para importar vários módulos do sistema de arquivos via import.meta.glob function :

const modules = import.meta.glob('./kinsta/*.js')

Isso gera a saída:

const modules = {
  './kinsta/isCool.js': () => import('./kinsta/isCool.js'),
  './kinsta/isAwesome.js': () => import('./kinsta/isAwesome.js'),
  './kinsta/isFun.js': () => import('./kinsta/isFun.js'),
}

O Vite também tem suporte para Glob Import As, para importar arquivos como strings usando import.meta.glob. Aqui está um exemplo de código:

const modules = import.meta.glob('./kinsta/*.js', { as: 'raw', eager: true })

Que será transformado nisto:

const modules = {
  './kinsta/rocks.js': 'export default "rocks"\n',
  './kinsta/rules.js': 'export default "rules"\n',
}

{ as: 'url' } também é compatível com o carregamento de ativos como URLs.

Por sua vez, o Webpack requer plugins adicionais, como webpack-import-glob-loader e glob-import-loader, para realizar importações globais. Eles expandirão isto:

import modules from "./test/**/*.js";

Para isto:

import * as moduleOne from "./foo/1.js";
import * as moduleTwo from "./test/bar/2.js";
import * as moduleThree from "./test/bar/3.js";

var modules = [moduleOne, moduleTwo, moduleThree];

14. Suporte a Web Workers

Web Workers são essenciais para executar tarefas pesadas em segundo plano sem congelar a página principal da web. Veja como o Vite e o Webpack lidam com eles:

O Vite facilita o uso de Web Workers. Você cria um arquivo separado de Web Worker, importa para o seu código principal e se comunica com ele. O Vite oferece duas maneiras de importar um worker em seu código principal:

  1. Os construtores new Worker() e o novo SharedWorker():
    const worker = new Worker(new URL('./worker.js', import.meta.url));
    
    // OR
    
    const worker = new SharedWorker(new URL('./worker.js', import.meta.url));
  2. Importados diretamente, anexando ?worker ou ?sharedworker:
    import MyWorker from './worker?worker';
    
    const worker = new MyWorker();
    
    myWorker.postMessage('Hello from the main thread!');

    O Webpack também oferece suporte a Web Workers e, a partir do Webpack 5, não é necessário usar um carregador para utilizar os workers.

    Const worker = new Worker(new URL('./worker.js', import.meta.url));

15. Capacidade de desenvolvimento de bibliotecas

Bibliotecas e frameworks habilitam os desenvolvedores a criar e compartilhar ferramentas que aceleram o desenvolvimento de aplicativos web. Tanto o Vite quanto o Webpack oferecem soluções robustas.

O Vite leva o desenvolvimento de bibliotecas a um novo patamar com seu Library Mode especializado, simplificando o processo de criação de bibliotecas voltadas para o navegador. Além disso, o Vite oferece a flexibilidade de externalizar dependências específicas, como Vue ou React, que você talvez prefira não incluir no seu pacote de bibliotecas.

O Webpack, por outro lado, é um empacotador versátil que também atende aos autores de bibliotecas. Se você usar o Webpack para criar uma biblioteca JavaScript, poderá configurá-lo para atender às suas necessidades exclusivas de empacotamento de bibliotecas. Ele permite que você defina como o código da sua biblioteca deve ser empacotado, o que o torna uma opção adequada para a criação de uma ampla variedade de bibliotecas.

16. Compatibilidade com o navegador

O Vite prioriza os navegadores modernos, visando aqueles com suporte nativo a módulos ES, como Chrome >=87, Firefox >=78, Safari >=14 e Edge >=88. Alvos personalizados também podem ser definidos via build.targetcomeçando em es2015. Os navegadores antigos têm suporte por meio de @vitejs/plugin-legacy.

O Webpack é compatível com todos os navegadores compatíveis com ES5 (exceto o IE8 e inferiores). Para acomodar os navegadores mais antigos, são necessários polyfills para recursos como import() e require.ensure().

Em termos de compatibilidade com o navegador, ambos são ótimos, mas a sua escolha deve depender do público-alvo do seu projeto e dos recursos do navegador.

Resumo

O Vite oferece desenvolvimento extremamente rápido com atualizações rápidas e amplas opções de personalização graças à sua abordagem de módulo ES nativo. Por outro lado, o Webpack, conhecido por sua robustez e amplo ecossistema, é excelente em builds de produção, mas exige uma curva de aprendizado mais acentuada.

Ao escolher entre o Vite e o Webpack, considere as necessidades do projeto e sua familiaridade com as complexidades da configuração. Ambos têm suas vantagens, portanto, escolha com base nos requisitos específicos do seu projeto.

Por fim, se estiver pensando em hospedar seus projetos com o Vite, você pode explorar a hospedagem de sites estáticos da Kinsta, que oferece uma solução robusta e eficiente para desenvolvedores web.

Compartilhe seu empacotador preferido e as principais considerações que orientaram sua escolha na seção de comentários abaixo.

Mostafa Said

I’m Mostafa, a full-stack developer with a knack for all things Laravel, Inertia, and JavaScript frameworks. When I'm not coding, you can find me sharing my knowledge through tutorials, diving into hackathons (and winning a few), and spreading the love for tech by teaching what I've learned.