En la naturaleza dinámica del JavaScript moderno, es esencial recordar que «viejo» no significa necesariamente «anticuado», y que «nuevo» no siempre implica «mejor».

La clave para elegir la tecnología adecuada reside en su alineación con las necesidades de tu proyecto. Este principio resuena con fuerza al considerar los bundlers de módulos JavaScript. Tanto si un bundler ha superado la prueba del tiempo como si se acaba de introducir, cada uno tiene sus ventajas y limitaciones.

Este artículo explora dos herramientas importantes y populares: Vite y Webpack. Evaluamos estos bundlers basándonos en sus características, distinciones, principios de diseño y cómo se integran en el ecosistema de los desarrolladores.

¿Qué es un Bundler de Módulos JavaScript?

Varios recursos siendo filtrados en un sistema
Bundler de Javascript

Un bundler de JavaScript es una herramienta utilizada en el desarrollo web para combinar varios archivos JavaScript en un único archivo, conocido como bundle. Simplifica la gestión del código JavaScript reduciendo el número de peticiones que debe realizar tu aplicación web, lo que en última instancia mejora el rendimiento.

Por ejemplo, considera que tienes dos archivos JavaScript separados: module1.js y module2.js. module1.js contiene lo siguiente:

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

Y module2.js contiene

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

Para empaquetar estos módulos en un único archivo, puedes utilizar un bundler como Rollup, Webpack o Parcel. Por ejemplo, si crearas un archivo index.js dentro del directorio de tu proyecto con el siguiente código

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

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

Al utilizar un bundler de JavaScript, combina module1.js, module2.js e index.js en un único paquete optimizado y adaptado al uso de tu aplicación web.

Aunque los navegadores web modernos admiten módulos ES y tecnologías como HTTP/2, que abordan los problemas de sobrecarga de las solicitudes, los bundlers de JavaScript siguen siendo indispensables para una serie de mejoras del código. Realizan transformaciones esenciales del código, como la minificación, la transpilación y la optimización.

Además, los bundlers de módulos JavaScript garantizan la compatibilidad entre distintos navegadores. Ayudan a resolver problemas específicos de los navegadores y garantizan una experiencia coherente para los usuarios, independientemente del navegador web que elijan.

Este proceso de agrupación no sólo acelera la velocidad de carga de tu aplicación web, sino que también garantiza un rendimiento eficaz, especialmente en entornos de producción. Ahora que ya conoces los paquetes de JavaScript y su papel en el desarrollo web, vamos a centrarnos en Vite y Webpack.

Vite y Webpack: Introducción y Visión General

Está claro que Vite y Webpack son líderes en el creciente campo del desarrollo web moderno, donde la gestión de recursos y los paquetes optimizados son vitales. Pero antes de entrar en una comparación detallada, echemos un vistazo rápido a estos bundlers y entendamos qué les hace destacar.

Vite: Desarrollo Rápido y Bajo Demanda

Vite, pronunciado «veet», cambia las reglas del juego para los desarrolladores web, priorizando la velocidad y la eficiencia. Lo que hace que Vite destaque es su enfoque de empaquetado bajo demanda. En lugar de pre-empaquetar todo el código y los activos, Vite aprovecha los módulos ES nativos de los navegadores modernos, sirviendo el código directamente al navegador durante el desarrollo. Esto conduce a una Sustitución de Módulos en Caliente (HMR, Hot Module Replacement) casi instantánea y a tiempos de arranque en frío reducidos.

El servidor de desarrollo de Vite brilla con este enfoque bajo demanda, permitiendo a los desarrolladores ver los cambios rápidamente sin una recompilación completa. También utiliza Rollup, para unas construcciones de producción eficientes. Como resultado, Vite ofrece un desarrollo rapidísimo y un sólido rendimiento en producción.

Webpack: Organizado y Adaptable

Webpack es la piedra angular del desarrollo web moderno, en constante evolución desde 2012. Lo mejor de Webpack es cómo organiza los componentes del sitio web. Optimiza los tiempos de carga y la experiencia del usuario organizando el código en módulos.

La adaptabilidad de Webpack es una ventaja notable. Los desarrolladores pueden personalizar los proyectos para tareas simples o complejas. Permite a los desarrolladores adaptar los flujos de trabajo y construir procesos con precisión.

Similitudes y Diferencias entre Vite y Webpack

Ahora que hemos comprendido los conceptos básicos de Vite y Webpack, exploremos sus similitudes y diferencias con más detalle. A medida que analizamos estos bundlers, examinamos varios aspectos para obtener una comprensión global de cómo se comparan y en qué destaca cada uno.

1. Arquitectura y Filosofía

Ambos bundlers ofrecen perspectivas únicas sobre la creación y optimización de aplicaciones web. Tienen en común su enfoque basado en plugins, que permite a la comunidad crear plugins adicionales beneficiosos que amplían su funcionalidad, convirtiéndolos en herramientas versátiles para los desarrolladores.

La filosofía central de Vite gira en torno a la simplicidad y la extensibilidad. Se adhiere a una estrategia minimalista, centrándose en los patrones de desarrollo de aplicaciones web más comunes. Este enfoque garantiza la mantenibilidad del proyecto a largo plazo.

La confianza de Vite en un sistema de plugins basado en rollups evita que el core se hinche al permitir la implementación de funciones a través de plugins externos. Esto promueve un core racionalizado y fomenta un próspero ecosistema de plugins bien mantenidos. Además, Vite colabora activamente con el proyecto Rollup para mantener la compatibilidad y un ecosistema de plugins compartido.

Webpack dota a los desarrolladores de personalización, permitiéndoles adaptar los proyectos a necesidades específicas, desde tareas básicas a esfuerzos complejos. Ofrece flexibilidad a la hora de configurar cada aspecto del proceso de construcción, lo que lo convierte en la elección perfecta para quienes buscan una experiencia de desarrollo personalizada.

Además, Webpack introduce el enfoque modular, similar al montaje de bloques de Lego para proyectos web. Todo en tu código base es un módulo para Webpack, y puede expresar sus dependencias de muchas maneras. Algunos ejemplos son:

  1. Declaración ES2015 import.
  2. Declaración CommonJS require().
  3. Declaración AMD define y require
  4. @import declaración dentro de un archivo css/sass/less.
  5. URL de imagen en un archivo de hoja de estilos url() o HTML <img src="">.

La Filosofía de Vite en Acción

La filosofía arquitectónica de Vite de ser ágil y extensible es evidente en su enfoque de la creación de aplicaciones web. Supón que estás desarrollando una aplicación web y quieres incluir funciones modernas de JavaScript, como los módulos ES. Con Vite, puedes hacerlo sin esfuerzo. Aquí tienes un ejemplo 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);

En este fragmento de código, Vite adopta el uso de módulos ES, y agrupa el código sobre la marcha sin esfuerzo, evitando los laboriosos pasos de agrupación durante el desarrollo. Este enfoque modular te permite gestionar eficazmente las dependencias, creando una base de código mantenible. Esto demuestra el compromiso de Vite con el minimalismo y las experiencias fáciles para el desarrollador.

La Filosofía de Webpack en Acción

La filosofía modular de Webpack es especialmente beneficiosa cuando se trabaja en proyectos a gran escala. Imagina que estás construyendo una aplicación web importante con varios módulos JavaScript. Con Webpack, puedes ensamblar perfectamente estos módulos, mejorando la legibilidad, la capacidad de mantenimiento y el tiempo de carga del sitio web. Aquí tienes un ejemplo 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/,
      },
    ],
  },
};

En este ejemplo, Webpack te permite configurar el proceso de construcción, optimizar el código y gestionar los activos de forma eficiente. Organizando tu proyecto en módulos y utilizando loaders como Babel, puedes escribir código limpio y modular que mejore la experiencia del usuario. Esto demuestra el compromiso de Webpack de proporcionar personalización y flexibilidad, garantizando que los desarrolladores puedan adaptar sus proyectos a necesidades específicas.

Aunque tanto Vite como Webpack tienen filosofías de diseño distintas, comparten el compromiso común de ampliar los límites del desarrollo web moderno. Vite se centra en patrones de programación modernos, promoviendo los Módulos ECMAScript (ESM) para el código fuente y fomentando estándares modernos como la nueva sintaxis Worker para los web workers.

Webpack, por su parte, evolucionó como respuesta a los retos planteados por Node.js y CommonJS, impulsando la adopción de módulos en el desarrollo web. La recopilación automática de dependencias de Webpack, junto con las mejoras de rendimiento, garantizan una experiencia fluida para el desarrollador.

2. Popularidad, Comunidad y Ecosistema

Vite y Webpack tienen líneas temporales distintas, que dan forma a su popularidad y comunidad.

Comparación de Vite y Webpack en Google Trends durante los últimos 5 años
Comparación de Vite y Webpack en Google Trends durante los últimos 5 años.

Vite es un recién llegado, que apareció en 2020. A pesar de su relativamente breve existencia, Vite ha ganado rápidamente atención, convirtiéndose en un protagonista prometedor en el campo del desarrollo web moderno.

En cambio, Webpack tiene una ventaja significativa, ya que se creó en 2012. Su tiempo en la industria le ha permitido desarrollar un ecosistema maduro y una comunidad robusta.

Comparación npmtrends para Vite y Webpack en los últimos 5 años.
Vite y Webpack en npmtrends en los últimos 5 años.

El gráfico anterior de npmtrends ilustra la comparación del número de descargas entre Vite y Webpack. Muestra claramente que Webpack mantiene sistemáticamente una posición destacada en términos de recuento de descargas, lo que pone de relieve su larga presencia y el alcance de su uso en la comunidad de desarrolladores.

Comparación de Vite y Webpack en star-history.
Comparación de Vite y Webpack en star-history.

Cuando miramos las estrellas de GitHub utilizando el historial de estrellas, que es una medida de la popularidad y el apoyo de la comunidad, encontramos que Vite cuenta con unas impresionantes 60.318 estrellas, mientras que Webpack mantiene una fuerte presencia con 63.598 estrellas. Estos recuentos de estrellas reflejan el reconocimiento y la participación activa en ambos proyectos. El rápido crecimiento de Vite y la popularidad sostenida de Webpack los convierten en activos valiosos dentro del panorama del desarrollo web.

3. Configuración y Facilidad de Uso

Tanto Vite como Webpack ofrecen numerosas opciones de configuración para adaptar tu paquete a tus necesidades específicas. Sin embargo, hay diferencias significativas que merecen tu atención. Exploremos la configuración y facilidad de uso de ambas herramientas.

Configuración Simplificada de Vite

Vite se distingue por su filosofía de configuración cero, diseñada para simplificar tu viaje por el desarrollo web. Esto significa que puedes crear una biblioteca básica de componentes Vue 3 con el mínimo esfuerzo. Aquí tienes una configuración de Vite sencilla para un proyecto de este tipo:

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

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

En el ejemplo anterior, sólo hemos importado e instalado el plugin oficial de Vite para Vue.js. La magia de Vite reside en su capacidad para autodetectar la configuración adecuada para la mayoría de los proyectos.

Complejidad de Configuración de Webpack

Webpack, por otro lado, tiende a requerir una configuración más detallada. Aunque ha avanzado hacia un enfoque de configuración cero en versiones recientes, no es tan automático como Vite. Para Vue 3, una configuración básica de Webpack podría tener este aspecto:

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(),
    ]
};

En comparación con Vite, la configuración de Webpack implica una configuración más manual. Las complejidades incluyen especificar rutas de entrada y salida, configurar cargadores para distintos tipos de archivos y configurar plugins para funcionalidades específicas. Desglosemos cada parte de la configuración y señalemos las complejidades:

  • Entrada y Salida: entry especifica el punto de entrada de tu aplicación, donde Webpack comenzará a empaquetar. En este caso, se establece en ./src/main.js, suponiendo que el archivo JavaScript principal de tu aplicación está en el directorio src, mientras que output define dónde deben guardarse los archivos empaquetados. La ruta de salida se resuelve con path.resolve, y el archivo empaquetado resultante se denomina bundle.js y se guarda en el directorio build.
  • Reglas de los Módulos: La sección module.rules define cómo se procesan los distintos tipos de archivos. En este caso, hay reglas para archivos JavaScript (babel-loader para la transpilación), componentes Vue de un solo archivo (vue-loader), y archivos CSS (vue-style-loader y css-loader para el manejo de estilos).
  • Configuración de Alias: La sección resolve.alias define alias para las importaciones de módulos. En este caso, configura un alias para Vue a vue/dist/vue.js.
  • Plugins: La sección de plugins incluye HotModuleReplacementPlugin, que habilita la sustitución en caliente de módulos, una función que te permite ver los cambios sin recargar toda la página durante el desarrollo, mientras queVueLoaderPlugin es necesaria para el procesamiento de componentes Vue de un solo archivo.

Para completar esta sección, Vite destaca por su facilidad de uso, ya que ofrece una configuración simplificada y una experiencia de desarrollo ágil. Sus mínimos requisitos de configuración y el uso de módulos ES nativos lo hacen ideal para principiantes y para un desarrollo rápido.

En cambio, la gran capacidad de configuración de Webpack, aunque beneficiosa para proyectos complejos, puede plantear dificultades a los desarrolladores principiantes. Su intrincada configuración y mantenimiento pueden ralentizar el desarrollo, especialmente en proyectos pequeños.

4. Servidor de Desarrollo

El servidor de desarrollo desempeña un papel crucial en el flujo de trabajo de un desarrollador, influyendo en la eficiencia y la productividad. Comparemos Vite y Webpack, evaluando el rendimiento y la usabilidad de su servidor de desarrollo para encontrar la herramienta superior para tu proyecto de desarrollo web.

Configuración del Servidor

Vite destaca por su servidor de desarrollo integrado y listo para usar, que a menudo elimina la necesidad de una configuración exhaustiva.

En cambio, Webpack ofrece flexibilidad pero requiere una configuración adicional. Los desarrolladores pueden elegir opciones como el Modo Vigilancia de Webpack, webpack-dev-server y webpack-dev-middleware para la compilación automática del código tras los cambios. Sin embargo, suele ser necesaria una configuración para establecer y afinar estas opciones.

Velocidad de Arranque en Frío

Las configuraciones tradicionales basadas en bundler implican un rastreo intensivo (eager crawling) y necesitan construir toda la aplicación antes de servirla, lo que provoca retrasos notables, sobre todo en proyectos complejos.

Vite revoluciona los arranques en frío con un enfoque fundamentalmente diferente, reduciendo drásticamente el tiempo de inicialización:

Captura de pantalla de la velocidad de empaquetado de esbuild para el proyecto three.js en comparación con otros empaquetadores
Esbuild el tiempo necesario para crear un paquete de producción de 10 copias de la biblioteca three.js desde cero utilizando la configuración predeterminada. (Fuente de la imagen: Esbuild)
  • Gestión Eficiente de Dependencias: Vite aprovecha esbuild, un bundler de alto rendimiento basado en Go, para preempaquetar dependencias, incluyendo JavaScript plano y módulos grandes. Todo ello contribuye significativamente a un arranque más rápido del servidor. Como parte de su proceso de preempaquetado, Vite optimiza el rendimiento fusionando las dependencias ESM con numerosos módulos internos en un único módulo.Por ejemplo, lodash-es contiene más de 600 módulos internos. Cuando se utilizan métodos tradicionales y se importa una función como debounce, se desencadenan más de 600 peticiones HTTP. La solución de Vite es agrupar previamente lodash-es en un solo módulo, reduciendo las peticiones HTTP a una sola. Esta drástica reducción de las peticiones aumenta significativamente la velocidad de carga de la página en el servidor de desarrollo.

    Gráfico del servidor de desarrollo basado en ESM
    Gráfico del servidor de desarrollo basado en ESM. (Fuente de la imagen: Vite)

  • Carga de Código Fuente Bajo Demanda: Vite utiliza módulos ES nativos para servir el código fuente, minimizando la carga y latencia del servidor. La transformación y el servicio del código fuente se producen a petición del navegador, mejorando la eficiencia y reduciendo los tiempos de espera.

    Gráfico del servidor de desarrollo basado en paquetes
    Gráfico del servidor de desarrollo basado en paquetes. (Fuente de la imagen: Vite)

Webpack, por otro lado, adopta un enfoque basado en paquetes, preempaquetando el código fuente y las dependencias, ampliando los tiempos de inicio del servidor durante el desarrollo. Comparado con la eficiente inicialización de Vite, el tiempo de configuración del servidor de Webpack es inherentemente más largo.

Sin embargo, el enfoque de carga bajo demanda de Vite puede introducir un ligero retraso cuando los usuarios navegan a rutas que requieren datos, CSS y activos adicionales. Esto se nota especialmente si estos recursos exigen más pasos de empaquetado. Por el contrario, la estrategia de Webpack garantiza que todos los datos del sitio estén disponibles, lo que conduce a una navegación más rápida del navegador a nuevas páginas dentro del servidor de desarrollo.

HMR (Sustitución en Caliente de Módulos,Hot Module Replacement)

Vite emplea HMR sobre ESM nativo, reduciendo la carga del servidor y la latencia al descargar parte del trabajo de empaquetado al navegador. Esto garantiza actualizaciones rápidas sin recargar toda la página, lo que es crucial para obtener información en tiempo real durante el desarrollo.

Webpack también es compatible con HMR, permitiendo actualizaciones en tiempo real y preservando el estado de la aplicación durante el desarrollo. Sin embargo, las limitaciones potenciales en el aprovechamiento de los módulos ES nativos pueden conducir a una mayor carga y latencia del servidor.

Rendimiento del Almacenamiento en Caché

El almacenamiento en caché es esencial para mejorar el rendimiento de las aplicaciones web, reduciendo la carga y los tiempos de construcción mediante la reutilización de los activos almacenados.

El almacenamiento en caché en Vite se gestiona con una caché del sistema de archivos, actualizando las dependencias en función de los cambios en package.json, lockfiles y vite.config.js. Optimiza las recargas de páginas almacenando en caché las peticiones de dependencias resueltas.

Webpack también utiliza la caché del sistema de archivos, borrando los archivos modificados en modo vigilancia, y purgando la caché antes de cada compilación en modo no vigilancia, lo que requiere una configuración personalizada para una caché óptima.

Para terminar la comparación entre servidores de desarrollo, Vite y Webpack ofrecen enfoques distintos para los servidores de desarrollo:

  • Vite proporciona un servidor de desarrollo listo para usar, minimizando la sobrecarga de configuración.
  • Webpack ofrece flexibilidad de configuración, pero requiere una configuración adicional.
  • Vite destaca en velocidad de arranque en frío y HMR para cambios rápidos de código.
  • Webpack rinde mejor en velocidad de navegación por el navegador gracias a los datos del sitio preempaquetados.
  • Ambos soportan HMR, pero tienen diferentes mecanismos de almacenamiento de módulos.
  • Vite gestiona la caché local y del navegador sin problemas, mientras que Webpack necesita una configuración personalizada.

5. Tiempo de Construcción y Tamaño del Bundle

Ahora vamos a comparar el tiempo de construcción y el tamaño del bundle entre Vite y Webpack, teniendo en cuenta la construcción de desarrollo, el cambio en caliente durante el servidor de desarrollo y la construcción de producción.

Nuestro entorno de pruebas incluye:

  • Ejecutar las pruebas en un MacBook Air con un chip Apple M1 y una GPU de 8 núcleos.
  • Un proyecto Vue 3 de escala media compuesto por 10 componentes, que utiliza Vuex para la gestión de estados y Vue Router para el enrutamiento.
  • Incorporación de hojas de estilo (CSS/SASS), activos como imágenes y fuentes, junto con un número moderado de dependencias.

Empecemos comparando el tiempo de empaquetado:

Vite [v4.4.11] Webpack [v5.89.0]
Primera construcción Dev 376ms 6s
Cambio en Caliente Instantáneo 1.5s
Desarrollo del Producto 2s 11s

Vite destaca como el claro ganador en velocidad de bundling, reduciendo drásticamente los tiempos de construcción. Aunque Webpack ofrece configurabilidad y herramientas de desarrollo robustas, va por detrás de Vite.

Vite [v4.4.11] (KB) Webpack [v5.89.0] (KB)
Tamaño del paquete de productos 866kb 934kb

Estas cifras se basan en una aplicación Vue.js de tamaño medio con un número moderado de dependencias. El tamaño real del paquete puede variar en función de la complejidad del proyecto, las dependencias y las técnicas de optimización.

El pequeño tamaño del bundle de Vite se debe a su eficiente preempaquetado con esbuild y módulos ES nativos.

El tamaño del paquete de Webpack puede optimizarse mediante varias opciones de configuración y plugins, pero generalmente produce paquetes más grandes debido a su exhaustivo proceso de bundling.

6. Optimización de la Construcción

Cuando se trata de optimizar el proceso de construcción en el desarrollo web moderno, Vite y Webpack ofrecen enfoques distintos, cada uno con su propio conjunto de características y capacidades. Profundicemos en la optimización de la construcción explorando las diferencias clave entre Vite y Webpack.

Generación de Directivas de Precarga

Vite genera automáticamente directivas <link rel="modulepreload"> para los fragmentos de entrada y sus importaciones directas en el HTML construido. Esto mejora los tiempos de carga al precargar eficazmente los módulos según sea necesario.

Así, puede tener este aspecto al inspeccionar la página:

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

Webpack no soportaba de forma nativa las sugerencias del navegador para los recursos. Pero a partir de Webpack v4.6.0, incluyó soporte para la prefetching y la preloading. Utilizar una directiva inline al declarar importaciones permite a Webpack emitir una sugerencia de recurso, que proporciona al navegador información sobre cuándo cargar el archivo importado. Por ejemplo

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

Esto mostrará:

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

División del Código CSS

Vite destaca por su enfoque racionalizado de la división del código CSS. Extrae automáticamente el CSS utilizado por los módulos en fragmentos asíncronos y genera archivos independientes. Esto significa que sólo se carga el CSS necesario a través de una etiqueta <link> cuando se carga el fragmento asíncrono asociado.

En particular, Vite se asegura de que el fragmento asíncrono sólo se evalúe después de cargar el CSS, lo que evita el Flash of Unstyled Content (FOUC). Como esta función está preconfigurada, puedes seguir importando tus archivos CSS sin pasos adicionales:

import './main.css';

Webpack proporciona flexibilidad pero requiere más configuración para la división del código CSS. Permite a los desarrolladores dividir el CSS utilizando varios plugins y opciones de configuración, como mini-css-extract-plugin.

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

División del Código y Carga de Fragmentos

La división del código es una técnica fundamental utilizada para dividir tu código en fragmentos más pequeños y manejables, cargando sólo lo que se necesita precisamente cuando se necesita. Esta práctica reduce significativamente los tiempos de carga iniciales y conserva recursos.

Enfoque de Vite para la Fragmentación

Hay casos en los que Vite utiliza Rollup para dividir el código en fragmentos separados automáticamente, como la carga dinámica o los puntos de entrada múltiples, y hay una forma de decirle explícitamente a Rollup qué módulos debe dividir en fragmentos separados mediante la opción output.manualChunks.

Aparte de la función preconfigurada de división de código de Vite, Vite también admite importaciones dinámicas con variables:

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

Vite también permite a los desarrolladores dividir trozos de proveedores utilizando la página oficial splitVendorChunkPlugin():

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

Con todas esas importaciones dinámicas y división de código, es habitual que el código se estructure en módulos o fragmentos, y que algunos de estos módulos se compartan entre distintas partes de una aplicación web. Vite reconoce los fragmentos comunes y optimiza el proceso de carga. Para entenderlo mejor, veamos el ejemplo de la documentación oficial de Vite.

Un gráfico que muestra los fragmentos comunes necesarios en dos fragmentos asíncronos.
Un gráfico que muestra los fragmentos comunes necesarios en dos fragmentos asíncronos. (Fuente de la imagen: Vite)

Sin optimización, cuando un usuario abre una sección de una aplicación web, llamémosla Section A, que depende del Common Chunk C (Fragmento Común C) de código compartido, el navegador comienza por obtener la Section A. Mientras analiza la Section A, se da cuenta de que necesita el Common Chunk C. Esto requiere un viaje adicional de ida y vuelta por la red, que puede ralentizar la carga inicial de la página:

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

Vite, en cambio, emplea una sofisticada función llamada Optimización Asíncrona de la Carga de Fragmentos. No espera a que el navegador descubra sus necesidades, sino que se prepara para ellas de forma proactiva. Cuando un usuario solicita la Section A, Vite envía simultáneamente la Section A y el Common Chunk C. Esta obtención paralela de los fragmentos necesarios acelera significativamente el proceso de carga:

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

Sin embargo, no se detiene ahí. El Common Chunk C puede tener sus propias dependencias, lo que podría causar más viajes de ida y vuelta en un escenario no optimizado. Vite no pasa por alto este aspecto. Analiza rigurosamente estas dependencias, asegurándose de que todo lo necesario — independientemente de su profundidad — se cargue eficientemente de una vez. Esto erradica la necesidad de viajes adicionales de ida y vuelta por la red, garantizando una aplicación web con gran capacidad de respuesta.

El enfoque de carga asíncrona de fragmentos de Vite optimiza el proceso de carga al obtener y servir proactivamente todos los fragmentos de código necesarios en paralelo. Esta eliminación de los viajes adicionales de ida y vuelta por la red se traduce en una experiencia web más ágil. Es como proporcionar un itinerario de viaje bien preparado para tu navegador, asegurando que recibe todos los recursos necesarios sin retrasos innecesarios.

Enfoque de Webpack para Dividir el Código

En cuanto a Webpack, hay tres técnicas generales disponibles para dividir el código:

  1. Puntos de entrada: Esta es la forma más sencilla de dividir un fragmento de código. Podemos simplemente definir un nuevo punto de entrada en el archivo config y Webpack lo añadirá como un trozo 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'),
       },
     };

    Sin embargo, este enfoque tiene limitaciones. Si los módulos se importan en fragmentos de entrada diferentes, acaban en ambos paquetes, lo que da lugar a código duplicado. Además, no es muy adaptable para dividir la lógica central de la aplicación cuando sea necesario.

  2. Evita la duplicación: Otro enfoque es utilizar las dependencias de entry o SplitChunksPlugin para dividir fragmentos, lo que ayuda a reducir la redundancia. Aquí tienes un ejemplo de cómo puedes configurar la división de código utilizando las dependencias de 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. Importaciones dinámicas: Por último, Webpack admite importaciones dinámicas, una valiosa característica para la carga de código bajo demanda. Utiliza una sintaxis conforme a la propuesta ECMAScript para las importaciones dinámicas. Este método es más flexible y granular, por lo que resulta adecuado para diversos escenarios de división de código.
    const { default: _ } = await import('lodash');

    También podemos utilizar los Comentarios Mágicos de Webpack (Webpack’s Magic Comments) para establecer un nombre para el fragmento, cargarlo de forma perezosa, especificar exportaciones de módulos y establecer una prioridad de obtención:

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

Tree-Shaking

Tree-shaking es una técnica de optimización crucial que tanto Vite como Webpack utilizan para recortar el tamaño de tus bundles de JavaScript.

Vite utiliza Rollup, que no sólo permite el uso de módulos ES, sino que también analiza estáticamente el código que importas. Esto significa que Vite puede excluir cualquier parte de un módulo que no utilices, lo que reduce el tamaño de los bundles. Por ejemplo, si tienes un módulo con varias funciones pero sólo utilizas una de ellas, Vite incluirá sólo esa función en el bundle. Aquí tienes un ejemplo sencillo:

  • Sin utilizar módulos ES, si quieres importar ajax desde ./utils.js, tendrías que importar todo el archivo.
    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);
  • El uso de módulos ES, en cambio, te permite importar sólo lo que necesitas, lo que da lugar a bibliotecas y aplicaciones más ligeras, más rápidas y menos complejas. Dado que Vite utiliza declaraciones explícitas import y export, puede realizar un tree-shaking muy eficaz sin depender únicamente de un minificador automatizado para detectar el código no utilizado.
    import { ajax } from './utils';
    const query = 'Kinsta';
    // Call the 'ajax' function
    ajax(`https://api.example.com?search=${query}`).then(handleResponse);

Por último, en el caso de Vite, podemos utilizar las opciones preconfiguradas de Rollup para el tree-shaking.

Webpack también admite tree-shaking, pero tiene un mecanismo diferente. Analiza las dependencias de tu código y elimina las partes no utilizadas durante el proceso de agrupación. Aunque es eficaz, puede no ser tan exhaustivo como el enfoque de Vite, sobre todo cuando se trata de módulos o bibliotecas grandes.

Además, según la documentación de Webpack debemos marcar los archivos como libres de efectos secundarios para garantizar que no eliminará ningún código que tenga otro código en producción que dependa de él.

La forma de conseguirlo es la propiedad sideEffects package.json:

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

Cabe señalar que también existe una opción de configuración similar para definir los efectos secundarios en las opciones de Rollup de Vite.

7. Gestión de Activos Estáticos

Los activos estáticos, como imágenes, fuentes y otros archivos, son una parte integral del desarrollo web. Vite y Webpack abordan el manejo de estos activos de forma diferente, cada uno con sus propios puntos fuertes y optimizaciones.

Gestión de Activos de Vite

El enfoque de Vite para manejar los activos estáticos es ágil y eficiente. Cuando importas un activo estático, Vite devuelve la URL pública resuelta cuando se sirve. Por ejemplo, cuando importas una imagen como ésta:

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

Durante el desarrollo, imgUrl se resolverá en /img.png. En la construcción de producción, se convertirá en algo como /assets/img.2d8efhg.png, optimizado para el almacenamiento en caché y el rendimiento.

Vite puede manejar estas importaciones con rutas públicas absolutas o rutas relativas, lo que lo hace flexible para las necesidades de tu proyecto. Este comportamiento se extiende a las referencias URL en CSS, que Vite maneja sin problemas.

Además, si utilizas Vite en un Componente de Archivo Único (SFC, Single File Component) de Vue, las referencias a activos en las plantillas se convierten automáticamente en importaciones, simplificando tu flujo de trabajo de desarrollo.

La gestión de activos de Vite va incluso más allá, ya que detecta los tipos de archivos comunes de imagen, medios y fuentes, que trata como activos. Estos activos se incluyen como parte del gráfico de activos de construcción, obtienen nombres de archivo con hash y pueden ser procesados por plugins para su optimización.

Gestión de Activos de Webpack

Webpack, por otro lado, tiene un enfoque diferente para la gestión de activos estáticos. Con Webpack, importas activos como haces habitualmente:

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

Webpack procesa esta importación añadiendo la imagen a tu directorio de salida y proporcionándote la URL final de la imagen. Esto facilita el trabajo con activos, y también funciona dentro de tu CSS utilizando url('./my-image.png'). css-loader de Webpack reconoce esto como un archivo local y sustituye la ruta por la URL final de la imagen en el directorio de salida. Lo mismo ocurre cuando se utiliza html-loader para <img src="./kinsta-image.png" />.

Los Módulos de Activos de Webpack introducidos en la versión 5 pueden manejar varios tipos de activos, no sólo imágenes. Por ejemplo, puedes configurar Webpack para que gestione archivos de fuentes:

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

Esta configuración te permite incorporar fuentes a tu proyecto mediante una declaración @font-face.

8. Soporte para Sitios Estáticos

Los sitios estáticos ofrecen numerosas ventajas, como tiempos de carga rápidos, seguridad mejorada y alojamiento simplificado. Un sitio estático se compone de HTML, CSS y JavaScript, proporcionando una experiencia de usuario optimizada y una entrega de contenidos eficiente. Tanto Vite como Webpack pueden ayudar a los desarrolladores a generar sitios estáticos de alto rendimiento, pero no con la misma eficacia.

El Enfoque de Vite para la Generación de Sitios Estáticos

Vite ofrece instrucciones específicas para el despliegue de sitios estáticos, aprovechando su enfoque racionalizado de desarrollo y despliegue, especialmente adecuado para sitios estáticos.

Otra cosa interesante de Vite es que tiene un script preview, que ayuda a los desarrolladores a lanzar localmente su construcción de producción para ver en acción el resultado final de su aplicación. Esta función permite a los desarrolladores probar y previsualizar su versión de producción antes de desplegarla en un servidor activo.

Sin embargo, es importante tener en cuenta que el script preview de Vite está pensado para previsualizar la construcción localmente y no para servir como servidor de producción. Esto significa que es una gran herramienta para que los desarrolladores prueben sus aplicaciones antes de desplegarlas, pero no es adecuada para alojar un sitio de producción activo.

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

Merece la pena destacar VitePress, una de las herramientas más potentes del ecosistema Vite. VitePress es un Generador de Sitios Estáticos (SSG, Static Site Generator) para generar sitios web rápidos y centrados en el contenido. VitePress toma tu texto fuente basado en Markdown, aplica un tema y genera páginas HTML estáticas que puedes desplegar rápidamente en Kinsta de forma gratuita.

El Enfoque de Webpack para la Generación de Sitios Estáticos

Aunque Webpack no está diseñado específicamente para la generación de sitios estáticos, se puede utilizar para crear sitios estáticos a través de varios plugins y configuraciones. Sin embargo, el proceso suele ser más complejo y menos ágil en comparación con Vite — El enfoque principal de Webpack reside en agrupar y optimizar módulos JavaScript, lo que lo convierte en una potente herramienta para crear aplicaciones web complejas.

9. Soporte de Renderizado del Lado del Servidor

La renderización del lado del servidor (SSR, Server-Side Rendering) es una técnica de desarrollo web que renderiza las páginas web en el servidor y envía el HTML completamente renderizado al navegador del cliente. Comparemos los dos paquetes en términos de compatibilidad con SSR:

  • Vite: Vite soporta la Renderización del Lado del Servidor, ofreciendo un enfoque racionalizado para las aplicaciones que requieren SSR. Con Vite, se pueden integrar a la perfección los frameworks front end que pueden ejecutar la misma aplicación en Node.js, pre-renderizarla en HTML, y posteriormente hidratarla en el lado del cliente. Esto convierte a Vite en una excelente opción para aplicaciones que exigen capacidades SSR, proporcionando a los desarrolladores las herramientas que necesitan para optimizar sus aplicaciones renderizadas en servidor.
  • Webpack: Webpack también puede utilizarse para el renderizado del lado del servidor. Sin embargo, la implementación de SSR con Webpack tiende a ser más intrincada y requiere un conocimiento más profundo de la configuración e instalación. Es posible que los desarrolladores tengan que invertir más tiempo en configurar SSR con Webpack en comparación con el enfoque más simplificado que ofrece Vite.

10. Soporte JSON

Tanto Vite como Webpack admiten la importación de archivos JSON. Excepto en Vite, también se admite la importación de JSON con nombre para ayudar con el tree-shaking

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

11. Soporte de Vue.js y JSX

Vue.js, un destacado framework JavaScript, sigue la sintaxis SFC (Componente de Archivo Único, Single File Component), simplificando el proceso de creación de interfaces de usuario. En cambio, JSX es una extensión de la sintaxis JavaScript, utilizada principalmente en React, que permite a los desarrolladores definir estructuras de interfaz de usuario utilizando etiquetas y elementos similares a HTML.

Vite ofrece soporte de primera clase para Vue.js con plugins oficiales que integran a la perfección Vite con Vue. También maneja archivos JSX (.jsx y .tsx) desde el primer momento, gracias a su transpilación esbuild. Los usuarios de Vue.js pueden utilizar el plugin @vitejs/plugin-vue-jsx, adaptado a Vue 3, que proporciona funciones como HMR, resolución global de componentes, directivas y slots.

En los casos en que se utilice JSX con otros frameworks como React o Preact, Vite permite configurar jsxFactory y jsxFragment personalizados mediante la opción esbuild. Este nivel de flexibilidad es valioso para proyectos que requieren la personalización de JSX.

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

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

Por otro lado, Webpack carece de soporte nativo para Vue.js o cualquier otra librería o framework específico. Los desarrolladores tienen que instalar los cargadores y dependencias pertinentes para configurar un proyecto para un framework JavaScript moderno, lo que lo convierte en un proceso más manual y potencialmente complejo.

12. Compatibilidad con TypeScript

Vite proporciona soporte nativo para TypeScript, permitiendo la incorporación sin problemas de archivos .ts en los proyectos. Utiliza el transpilador esbuild para una rápida transformación del código durante el desarrollo. Vite se centra en la transpilación, no en la comprobación de tipos. Espera que tu IDE y tu proceso de construcción se encarguen de la comprobación de tipos.

Webpack carece de compatibilidad nativa con TypeScript, por lo que los desarrolladores tienen que configurar manualmente TypeScript utilizando el compilador typescript y la función ts-loader. Esto requiere configurar tsconfig.json para especificar las opciones de TypeScript. Una vez configurado, Webpack utiliza ts-loader para compilar el código TypeScript. Aunque esto introduce pasos de configuración adicionales, proporciona flexibilidad y compatibilidad con otras características de Webpack.

13. Compatibilidad con Glob Import

Vite es compatible con Glob Import. Esta función se utiliza para importar múltiples módulos desde el sistema de archivos a través de import.meta.glob function:

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

Esto mostrará:

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

Vite también tiene soporte para Glob Import As, para importar archivos como cadenas utilizando import.meta.glob. Aquí tienes un ejemplo de código:

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

Que se transformará en esto

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

{ as: 'url' } también es compatible para cargar activos como URL.

Mientras que Webpack requiere plugins adicionales como webpack-import-glob-loader y glob-import-loader para realizar Importaciones Glob. Ellos ampliarán esto:

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

En esto:

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. Soporte para Web Workers

Los Web Workers son esenciales para ejecutar tareas pesadas en segundo plano sin congelar la página web principal. A continuación te explicamos cómo los gestionan Vite y Webpack:

Vite facilita el uso de Web Workers. Creas un archivo Web Worker independiente, lo importas a tu código principal y te comunicas con él. Vite ofrece dos formas de importar un worker en tu código principal:

  1. new Worker() y los nuevos constructores 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 directamente añadiendo ?worker o ?sharedworker:
    import MyWorker from './worker?worker';
    
    const worker = new MyWorker();
    
    myWorker.postMessage('Hello from the main thread!');

    Webpack también admite Web Workers, y a partir de Webpack 5, no es necesario utilizar un cargador para utilizar workers.

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

15. Capacidad de Desarrollo de Bibliotecas

Las bibliotecas y los frameworks de trabajo permiten a los desarrolladores crear y compartir herramientas que aceleran el desarrollo de aplicaciones web. Tanto Vite como Webpack ofrecen soluciones robustas.

Vite lleva el desarrollo de bibliotecas al siguiente nivel con su Modo Biblioteca especializado, que simplifica el proceso de creación de bibliotecas centradas en el navegador. Además, Vite ofrece la flexibilidad de externalizar dependencias específicas, como Vue o React, que tal vez prefieras no incluir en tu paquete de bibliotecas.

Webpack, por otro lado, es un bundler versátil que también atiende a los autores de bibliotecas. Si utilizas Webpack para crear una biblioteca JavaScript, puedes configurarlo para que se adapte a tus necesidades específicas de empaquetado de bibliotecas. Te permite definir cómo debe empaquetarse el código de tu biblioteca, lo que lo convierte en una opción adecuada para crear una amplia gama de bibliotecas.

16. Compatibilidad con Navegadores

Vite da prioridad a los navegadores modernos, centrándose en aquellos con soporte nativo de ES Modules, como Chrome >=87, Firefox >=78, Safari >=14, y Edge >=88. También pueden establecerse objetivos personalizados mediante build.target a partir de es2015. Los navegadores heredados son compatibles a través de @vitejs/plugin-legacy.

Webpack admite todos los navegadores compatibles con ES5 (excepto IE8 e inferiores). Para adaptarse a los navegadores más antiguos, se necesitan polyfills para funciones como import() y require.ensure().

En términos de compatibilidad con navegadores, ambos son excelentes, pero tu elección debe depender del público objetivo de tu proyecto y de las capacidades de su navegador.

Resumen

Vite ofrece un desarrollo rapidísimo con actualizaciones rápidas y amplias opciones de personalización gracias a su enfoque de módulos ES nativos. Por el contrario, Webpack, conocido por su robustez y amplio ecosistema, destaca en las construcciones de producción, pero requiere una curva de aprendizaje más pronunciada.

Al elegir entre Vite y Webpack, ten en cuenta las necesidades del proyecto y tu familiaridad con las complejidades de la configuración. Ambos tienen sus ventajas, así que elige en función de los requisitos específicos de tu proyecto.

Por último, si estás pensando en alojar tus proyectos impulsados por Vite, puedes explorar el Alojamiento de Sitios Estáticos de Kinsta, que ofrece una solución robusta y eficiente para desarrolladores web.

Comparte tu bundler preferido y las consideraciones clave que guían tu selección en la sección de comentarios más abajo.

Mostafa Said

Soy Mostafa, un desarrollador full-stack con un don para todo lo relacionado con Laravel, Inertia y frameworks JavaScript. Cuando no estoy programando, puedes encontrarme compartiendo mis conocimientos a través de tutoriales, participando en hackatones (y ganando unos cuantos) y difundiendo el amor por la tecnología enseñando lo que he aprendido.