¿Qué es Webpack?

Desarrollo Web

Webpack es un empaquetador de módulos. Nuestro sitio normalmente tiene muchos assets como imagenes, archivos JS, archivos CSS, archivos SCSS, entre otros. Para optimizar el empaquetamiento, Webpack provee un conjunto de loaders y plugins para hacer esto.

¿Qué es Webpack?

Como su página oficial dice, es un empaquetador de módulos estáticos para aplicaciones JavaScript modernas, lo cual quiere decir que ayuda a convertir nuestros assets de una manera rápida, mapeando cada archivo y procesándolo de acuerdo a una configuración para generar uno o más bundles.

Para darnos una idea, veamos la siguiente imagen

Webpack structure

Podemos ver que, dado un conjunto de archivos como js (javascript), ts (typescript), sass (sass), etc, pasan por webpack quien se encarga, a partir de las configuraciones, de crear archivos comprimidos y listos para producción.

¿Por qué Webpack?

A lo largo del tiempo han existido muchas herramientas con el mismo propósito o similares. Grunt, Gulp o Browserify, tienen características de parecidas a las de Webpack, Grunt y Gulp son automatizadores de tareas, dados un conjunto de plugins y configurándolo podíamos crear nuestros bundles de una manera sencilla y rápida, automatizando tareas. Browserify es un poco más sencillo, ya que es más sencillo, la desventaja de grunt y gulp es que hay que hacer muchas configuraciones para tareas que realmente no cambian mucho de proyecto en proyecto, Browserify hace esto más simple ya que solo hay tomar el archivo principal y se encarga de empaquetarlo de acuerdo a todos los require que encuentre en la aplicación, más no en grunt o gulp que había que decirle que archivos empaquetar.

Webpack tiene todos los beneficios de estos tres, pero es mucho más rápido y más sencillo de configurar. Tiene las ventajas y características de Browserify pero puede ser extensible, mediante Loaders y Plugins, para archivos diferentes a JS o tareas más específicas.

En este momento, deberíamos dejar de lado Grunt, Gulp o Browserify y usar solo webpack para nuestras futuras aplicaciones.

Webpack se basa en 2 tipos de herramientas, una son los Loaders y otra los Plugins.

¿Qué es un Loader?

Un loader es un preprocesador de archivos. Webpack solo sabe trabajar, de manera nativa, con archivos JavaScript, más sin embargo, normalmente nuestros assets no son solo archivos js, si no archivos como imágenes (.png, .jpg, .gif), fuentes (.ttf, .wof), preprocesadores css (.sass, .stylus, .less), etc. Por lo tanto, los loaders nos ayudan a saber tratar estos archivos con tareas básicas sobre ellos.

¿Qué es un Plugin?

Un Plugin es aquella herramienta que extiende las capacidades de webpack, es decir, agrega funcionalidades extras como copiar archivos, concatenar archivos, etc.

Crear un proyecto usando Webpack

Vamos a la carpeta donde estará nuestro proyecto desde la terminal y lo inicializamos

npm init -y

En caso de no tener instalado Webpack en nuestra PC, solo tenemos que instalarlo de manera global

npm install -g webpack

Ahora creamos un archivo en la raíz de la carpeta llamado index.js, un archivo index.html y una carpeta llamada dist, donde compilará nuestro código. En el archivo index.js escribimos una línea alert('Hola mundo Webpack'). Para finalizar solo tenemos que crear nuestro archivo html con referencia al archivo dist/bundle.js.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="dist/bundle.js"></script>
</body>
</html>

Vamos a la terminal y tecleamos:

webpack index.js dist/bundle.js

Se generará nuestro bundle, ya solo tenemos que abrir nuestra página web y nos mostrará el alert que escribimos.

Archivo de configuración

Webpack nos provee de un mecanismo para poder hacer las configuraciones de nuestros loaders, plugins, configurar el entry point, etc. Este archivo lo podemos llamar como queramos, pero normalmente se nombra webpack.config.js, así que lo crearemos con ese nombre. Su estructura es como la de un módulo en JS, usando la notación de objetos de JavaScript para definir las configuraciones.

module.exports = {
    entry: './index.js',
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist",
    }
}
  • entry: Archivo de entrada o como se le conoce, entry point.
  • output: donde traspilará el código, donde filename es el archivo y path la carpeta donde se creará el archivo.

Ahora, solo escribimos webpack y creará el archivo. Tomará el archivo de configuración webpack.config.js, pero en caso de haber creado el archivo con otro nombre solo tenemos que escribir webpack --config=otronombre.config.js y tomará el archivo de configuración que se le pase a la bandera --config.

Loaders

Vamos a configurar unos loaders. Los archivos JS pueden contener un css dentro. Para algunos esto sonará un poco raro, pero podemos insertar archivos css dentro de nuestros archivos JS y modificar los estilos desde JS. Solo tenemos que instalar el css-loader

npm install --save-dev css-loader

Una vez instalado solo hay que configurarlos en nuestro webpack.config.js. Los loaders son configurados dentro de module.rules.

module.exports = {
    entry: './index.js',
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist",
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['css-loader'],
            }
        ]
    }
}

Podemos observar que rules es un array con un conjunto de reglas en forma de objetos con 2 propiedades, test donde especificamos el tipo de archivo a usar en forma de regex. La segunda propiedad use es donde ponemos el o los loaders a utilizar para los tipos de archivos especificados en test.

Ahora solo falta importar el archivo css en nuestro archivo index.js.

import './css/styles.css';

alert('Hola mundo webpack');

Importamos el archivo css en nuestro archivo, creamos nuestro archivo css en una carpeta css. Nuestra estructura quedaría de la siguiente forma:

Estructura Webpack

En nuestro archivo style.css escribimos algo simple

body{
    background-color: red;
}

Finalmente, corremos webpack en la terminal y vamos a nuestro navegador, al recargar vemos que no se han aplicado nuestros estilos. Lo anterior ocurre ya que css-loader únicamente da soporte para poder interpretar archivos con extensión css, más sin embargo, no tiene una otra funcionalidad como poder aplicar los estilos a nuestros selectores definidos en css, para esto, existe otro loader llamado style-loader el cual se encarga de hacer una inyección de una etiqueta style en la cabecera de nuestro archivo html. Vamos a configurarlo.

Descargamos style-loader con npm

npm install style-loader --save-dev

Lo configuramos dentro de nuestras reglas en nuestro webpack.config.js

module.exports = {
    entry: './index.js',
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist",
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            }
        ]
    }
}

Finalmente, ejecutamos webpack y al ir a nuestro navegador y recargar veremos el resultado, nuestro body tendrá un background de color rojo.

Plugins

Los plugins son todo aquello que los loaders no pueden hacer, normalmente acciones más complejas que requieran más opciones como parámetros adicionales. Uno de los plugins más famosos es extract-text-webpack-plugin con el que podemos crear un archivo separado de nuestro bundle, es decir, leemos un archivo y creamos un archivo .css para nuestro caso, por lo que, ya no utilizaremos style-loader si no una herramienta como extract-text-webpack-plugin para crear un archivo css por separado.

Vamos a crear otros 2 archivos css, uno llamado fuentes.css y otro links.css

/*fuentes.css*/
p{
    font-size: 20px;
    background-color: white;
    margin: 10px 0;
    padding: 5px;
    font-family: 'Times New Roman', Times, serif;
}
/*links.css*/
a{
    color: blue;
}
a:hover{
    color: green;
}

Los importamos en index.js

import './css/styles.css';
import './css/links.css';
import './css/fuentes.css';

alert('Hola mundo webpack');

Editamos nuestro index.html un poco, agregando un tag link con la referencia a nuestro archivo que generaremos style.css y algunas etiquetas p y a.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="dist/styles.css">
</head>
<body>
    <div class="content">
        <p>Línea 1 de etiqueta p</p>
        <p>Línea 2 de etiqueta p y con <a href="#">etiqueta a</a></p>
    </div>
    <script src="dist/bundle.js"></script>
</body>
</html>

Instalamos el plugin

 npm install extract-text-webpack-plugin --save-dev

Lo configuramos en nuestro archivo webpack.config.js. Los plugins al ser herramientas deben ser importados, por lo que, al inicio de nuestro archivo lo importamos como cualquier módulo en JS, después tenemos que instanciarlo en plugins dentro de nuestro archivo de configuración y al final lo usamos dentro de nuestras reglas.

const ExtractTextPlugin = require("extract-text-webpack-plugin");//importamos el módulo

module.exports = {
    entry: './index.js',
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist",
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                //use: ['style-loader', 'css-loader'],
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',//usamos el plugin, aquí le indicamos que loader usar antes de empaquetarlo
                    fallback: 'style-loader'//en caso de no funcionar el plugin, que use este loader
                }),
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("styles.css"),//instanciamos el módulo indicandole el archivo de salida
    ]
}

Al ejecutar webpack nos mandará un error que no se encuentra el módulo Chunk, para solucionarlo solo debemos instalar webpack de manera local al proyecto, esto ya que como lo indican en el siguiente hilo de discusión Hilo de discusión error Chunk es un bug de webpack en su versión 3.

Instalamos webpack local

npm install --save-dev weback@3.6.0

Una vez instalado ejecutamos webpack y veremos que nos crea un archivo styles.css, en nuestro navegador revisamos y tenemos los cambios que esperabamos.

Flag --watch

Si lo que queremos es no estar corriendo cada que hagamos un cambio el comando webpack, podemos usar el flag --watch

webpack --watch

Ahora, al momento de hacer un cambio a alguno de nuestros archivos se generará de manera automática los bundles.

Conclusión

Con webpack podemos crear nuestros bundles de una manera sencilla y rápida, basta algunas configuraciones iniciales.

Estaremos publicando post sobre webpack con temas como el uso de babel para traspilar código de ECMAScript2015 a ES5, webpack-dev-server como servidor de desarrollo, trato de preprocesadores less, sass y stylus y optimización con Commons Chunk Plugin, Dll Plugin y Dll Reference Plugin.