Webpack es un empaquetador de módulos, es decir, te permite generar un achivo único con todos aquellos módulos que necesita tu aplicación para funcionar. Para darte una idea, te permite incluir todos tus archivos javascript .js en un único archivo, incluso se pueden incluir hasta archivos de estilos .css en el mismo archivo, llamado *.bundle.js. Además se puede realizar otras tareas de optimización de los códigos, tales como la minificación y la compresión.
Angular App Tool: Digitalize polygons by Victor Valencia Rico
Tabla de contenido
Introducción
Webpack es una herramienta configurable que nos ayudará a realizar algunas tareas básicas en el desarrollo Frontend en tareas automatizadas y preparar nuestra aplicación web para producción.
Antes de entrar de lleno con Webpack, es importante aclarar unos conceptos básicos previos que nos ayudarán a entender mejor cómo funciona esta herramienta:
-
Entry Point
Indican a Webpack los archivos de entrada para generar los paquetes o archivos *.bundle.js.
-
Output
Indican a Webpack el lugar donde se colocarán los paquetes *.bundle.* que se hayan generado: JavaScript, CSS, HTML, etc.
-
Loaders
Son las rutinas que hacen posible que Webpack cargué, transforme y procese todos los archivos o entradas.
-
Plugins
Amplían las funcionalidades por defecto que incluye Webpack. Permiten realizar tareas en el código de nuestra aplicación como la optimización, minificación, ofuscación, por mencionar algunas.
Proyecto inicial (Sin Webpack)
Como proyecto inicial tenemos un simple blog de ejemplo. El proyecto web esta realizado en Vue.js y Bootstrap. La siguiente imagen muestra el resultado final de este proyecto:
La estructuta inicial de este proyecto es la siguiente:
Proyecto/
├─ src/
├── css/
│ ├─ app.css
├── js/
│ ├─ app.js
| index.html
A continuación se muestra el contenido de los 3 archivos del proyecto.
src/css/app.css
/* src/css/app.css */
/*!
* App.css v0.0.1
* (c) 2020 Victor Valencia Rico
* Released under the MIT License.
*/
body {
background-color: #efefef;
}
body > p {
color: #220052;
}
En el archivo app.css se definen los estilos del proyecto.
src/js/app.js
En el archivo app.js se define la lógica y los componentes que utiliza Vue.js para hacer el despliege de las entradas del blog.
index.html
En el archivo index.html representa la vista y se hace referencia a las librerías Vue.js y Bootstrap vía CDN.
Hay que tomar en cuenta que este proyecto no esta usando Webpack.
Ahora nuestro objetivo principal será incluir Webpack para generar un solo archivo app.bundle.js, como se muestra en la siguiente imagen:
Empaquetaremos los estilos de la librería de Bootstrap -> bootstrap.min.css, el archivo de estilos del proyecto app.css, la librería de Vue.js -> vue.js y el script del proyecto app.js en el archivo final app.bundle.js
Angular App: Todo List by Victor Valencia Rico
Requerimientos
La instalación de Webpack es relativamente simple, únicamente necesitamos la previa instalación de NodeJS, junto con el gestor de paquetes npm para descargar Webpack:
node >= 8.0 o mayor
$ node --version
npm >= 5.0 o mayor
$ npm --version
El siguiente paso será cambiarnos a la carpeta del proyecto y ejercutar el comando npm init:
$ cd Proyecto
$ npm init
Con el comando npm init generaremos el archivo de configuración básico llamado package.json, para iniciar con nuestro tutorial, tendremos que ingresar algunos datos en la terminal, otra manera es creando el archivo package.json de la siguiente manera:
// package.json
{
"name": "webpack-tutorial",
"version": "0.0.1",
"description": "Tutorial de Webpack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Instalación de Webpack
Ahora instalamos webpack de manera global:
$ npm i -g webpack
Para comprobar la correcta instalación de Webpack y la versión que se ha instalado escribimos:
$ webpack --version
# 4.43.0
En este tutorial la versión instalada de Webpack es v4.43.0
Angular App Tool: Digitalize polygons by Victor Valencia Rico
Proyecto inicial (Webpack en Acción)
Una vez instalado Webpack continuamos con la configuración e instalación de algunos paquetes adicionales o plugins que necesitaremos para realizar ciertas acciones a nuestro código.
Iniciamos con la instalación de las librerías de nuestro proyecto: Vue.js y Bootstrap para incluirlas en nuestro archivo final app.bundle.js
$ npm i bootstrap vue --save-dev
Adicional a esto, instalamos los Loaders: style-loader y css-loader
$ npm i style-loader css-loader --save-dev
La función de estos Loaders es la siguiente: style-loader inyecta CSS en el DOM y css-loader interpreta los @import y url() como import/require() y los resuelve.
A continuación crearemos nuestro archivo webpack.config.json el cual contedrá nuestra configuración de Webpack de la siguiente manera:
// webpack.config.json
const path = require('path');
module.exports = {
entry: {
app: './src/all.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
Antes de ejecutar esta configuración, necesitamos crear el archivo src/all.js, el cual tendrá la función de Entry Point y deberá contener todos lo necesario para que nuestro proyecto funcione.
// all.js
// Styles
import "bootstrap/dist/css/bootstrap.min.css";
import "./css/app.css";
// Scripts - App
import './js/app.js';
Notemos que este archivo importa los estilos de la librería Bootstrap y nuestros estilos del archivo css/app.css y por último importamos el archivo js/app.js que contiene toda la lógica del proyecto.
Además modificaremos el archivo src/js/app.js agregando la importación de Vue.js
/* src/js/app.js */
/*!
* App.js v0.0.1
* (c) 2020 Victor Valencia Rico
* Released under the MIT License.
*/
import Vue from 'vue/dist/vue.min.js';
// ... Resto del código
Listo, ya tenemos nuestra configuración lista para ejecutar y generar el archivo app.bundle.js. Ahora, ejecutamos el comando webpack de la siguiente manera:
$ webpack
# Hash: ffb7a993d043380baa09
# Version: webpack 4.43.0
# Time: 918ms
# Built at: 2020-05-12 11:21:33
# Asset Size Chunks Chunk Names
# app.bundle.js 289 KiB app [emitted] app
# Entrypoint app = app.bundle.js
El Output o archivo de salida se generará sobre en la carpeta dist con el nombre app.bundle.js. Por último, necesitamos modificar nuestro archivo index.html para hacer referencia a nuestro archivo final app.bundle.js
Si visitamos ahora nuestro proyecto deberiamos de obtener el mismo resultado final, pero ahora en vez de cargar los 2 archivos de los estilos y los 2 scripts de nuestra aplicación, solo cargaremos un solo script en el cual estan empaquetados los estilos y los scripts mencionados anteriormente, lo cual hace que el proyecto cargue mas rápido:
Si deseamos realizar un cambio en nuestros estilos o en el código de nuestro proyecto sería muy tedioso estar ejecutando el comando webpack cada que realicemos un cambio, para solucionar esto, es más práctico y recomendable ejercutar el siguiente comando:
$ webpack --w
# webpack is watching the files…
Al hacer esto le estamos diciendo a Webpack que cada que haya un cambio en nuestros archivos de entrada o Entry Point, realice la construcción de nuestra salida o Output.
Mejoras con Webpack
En el ejemplo anterior estuvimos ejecutando Webpack en modo development o desarrollo por Default, pero si necesitamos generar nuestro archivo app.bundle.js para ponerlo en producción e inclusive webpack realice algunas tareas de optimización a nuestro código, ejecutamos el siguiente comando:
$ webpack --mode=production
Cuando se ejecuta Webpack en modo producción y el archivo generado rebasa los 244 kB, Webpack recomienda no rebasar el tamaño recomendado. En nuestro caso, el archivo generado rebasa lo recomendado con un tamaño de 258 kB. Como se muestra en la siguiente imagen:
Para reducir el tamaño lo primero que necesitamos hacer es separar los estilos en un paquete que contenga solo los estilos y otro paquete que contenga todos los scripts, de esa manera reduciremos el tamaño, para realizar esta funcionalidad ocuparemos instalar el siguiente plugin mini-css-extract-plugin:
$ npm i mini-css-extract-plugin --save-dev
Ahora modificamos nuestra configuración en el archivo webpack.config.json de la siguiente manera:
// webpack.config.json
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: {
app: './src/all.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].bundle.css',
})
]
};
Listo, ya tenemos nuestra configuración lista. Ahora, ejecutamos el comando webpack en modo development de la siguiente manera:
$ webpack --mode=development
# Hash: ae6bfd740bc24c0ed3f8
# Version: webpack 4.43.0
# Time: 1056ms
# Built at: 2020-05-12 11:45:30
# Asset Size Chunks Chunk Names
# app.bundle.css 156 KiB 0 [emitted] app
# app.bundle.js 119 KiB 0 [emitted] app
# Entrypoint app = app.bundle.css app.bundle.js
Ahora tendremos 2 bundlers, uno con la extensión .css y otro con la extensión .js, notamos también que cada uno de ellos no rebasa los 244 kB, como se muestra en la siguiente imagen:
Ahora, si ejecutamos el comando webpack en modo production, notaremos que habrá una reducción en el archivo app.bundle.js, reduciendose en 21 kB:
$ webpack --mode=production
# Hash: 701a8d25b33a2317a015
# Version: webpack 4.43.0
# Time: 2595ms
# Built at: 2020-05-12 11:51:30
# Asset Size Chunks Chunk Names
# app.bundle.css 156 KiB 0 [emitted] app
# app.bundle.js 97.9 KiB 0 [emitted] app
# Entrypoint app [big] = app.bundle.css app.bundle.js
Ahora solo haremos referencia al archivo app.bundle.css en nuestro archivo index.html, como se muestra a continuación:
Si visitamos nuevamente nuestro proyecto deberiamos de obtener el mismo resultado final que el anterior, solo que estarán separados los archivos de los estilos en el arhivo app.bundle.css y los scripts en el archivo app.bundle.js:
Wheater Dasboard: Angular + OpenWeather by Victor Valencia Rico
Minificación
Ahora nos enfocaremos en minificar el código para reducir aun más, el tamaño de los bundlers. Para los scripts o archivos .js no es necesario instalar ningun plugin o dependencia, pues Webpack es capaz de minificarlo y ofuscarlo simplemente estableciendo el modo de producción --mode=production. Sin embargo los estilos o archivos .css requiere de un plugin.
Por ejemplo: Si abrimos nuestro arhivo app.bundle.css y nos movemos hacia el final del archivo, notaremos que agregó nuestro archivo app.css sin realizar ninguna minificación, lo reemplazo por el archivo original, como se muestra a continuación:
/* dist/app.bundle.css */
/* ... Resto del código */
/*!
* App.css v0.0.1
* (c) 2020 Victor Valencia Rico
* Released under the MIT License.
*/
body {
background-color: #efefef;
}
body > p {
color: #220052;
}
A continuación instalaremos el plugin optimize-css-assets-webpack-plugin para realizar la minificación de los estilos:
$ npm i optimize-css-assets-webpack-plugin --save-dev
Ahora modificamos nuestra configuración en el archivo webpack.config.json de la siguiente manera:
// webpack.config.json
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
entry: {
app: './src/all.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].bundle.css',
}),
new OptimizeCSSAssetsPlugin({})
]
};
Ahora, si ejecutamos el comando webpack en modo production, notaremos que habrá una reducción en el archivo app.bundle.css, reduciendose en 2 kB:
$ webpack --mode=production
# Hash: f9fa29d7316db86003d5
# Version: webpack 4.43.0
# Time: 3731ms
# Built at: 2020-05-12 12:00:19
# Asset Size Chunks Chunk Names
# app.bundle.css 154 KiB 0 [emitted] app
# app.bundle.js 97.9 KiB 0 [emitted] app
# Entrypoint app [big] = app.bundle.css app.bundle.js
Abrimos nuevamente nuestro arhivo app.bundle.css y nos movemos hacia el final del archivo, notaremos que el código se encontrará minificado, como se muestra a continuación:
/* dist/app.bundle.css */
/* ... Resto del código */
/*!
* App.css v0.0.1
* (c) 2020 Victor Valencia Rico
* Released under the MIT License.
*/body{background-color:#efefef}body>p{color:#220052}
Webpack Bundle Analyzer
En proyectos muy complejos configurar Webpack puede tomar bastante tiempo y esfuerzo, se llega a un punto en el que procesar mentalmente todo lo que hace cada Loader y cada Plugin es muy difícil. Afortunadamente podemos simplificar y analizar los resultados con webpack-bundle-analyzer.
A continuación instalaremos el plugin webpack-bundle-analyzer para realizar la minificación de los estilos:
$ npm i webpack-bundle-analyzer --save-dev
Ahora modificamos nuestra configuración en el archivo webpack.config.json de la siguiente manera:
// webpack.config.json
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: {
app: './src/all.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].bundle.css',
}),
new OptimizeCSSAssetsPlugin({}),
new BundleAnalyzerPlugin()
]
};
Ejecutamos el comando webpack en modo production.
$ webpack --mode=production
Después de ejecutarse el comando notaremos que se abrirá la siguiente ventana en nuestro navegador:
Webpack Bundle Analyzer desplegará una gráfica interactiva con el resultado de nuestro bundle, qué dependencias contiene y cuánto pesan cada una de ellas.
Existen 3 modos de la vista en este gráfico:
stat: Muestra el tamaño de los archivos de entrada antes de ser procesados por Webpack.
parsed: Muestra el tamaño de los archivos de salida ya procesados. Si se usa uglify por ejemplo, se vería una diferencia significativa.
gzip: Muestra el tamaño de los archivos ya procesados y pasados por compresión gzip.
Angular App Tool: Digitalize polygons by Victor Valencia Rico
Compresión
La compresión generalmente se refiere al código que se ha modificado utilizando un algoritmo de compresión de datos. A diferencia de la minificación que termina proporcionando un código perfectamente válido, el código comprimido debe descomprimirse antes de usarse.
Con cada solicitud y respuesta HTTP, los navegadores y los servidores web pueden agregar Headers para incluir información adicional sobre el activo que se busca o se recibe. Cuando el navegador envia en el Request Header la opción accept-encoding especifica qué formatos de codificación de contenido o algoritmos de compresión admite.
Existen muchos algoritmos de compresión de texto, pero solo hay 3 compatibles para la compresión (y descompresión) de las solicitudes HTTP
Deflate deflate: No se usa comúnmente.
Gzip gzip: El formato de compresión más utilizado para las interacciones de servidor y cliente. Se basa en el algoritmo Deflate y es compatible con todos los navegadores actuales.
Brotli br: Un algoritmo de compresión más nuevo que tiene como objetivo mejorar aún más las relaciones de compresión, lo que puede resultar en cargas de página aún más rápidas. Es compatible con las últimas versiones de la mayoría de los navegadores.
Para terminar con nuestro tutorial, generaremos una versión comprimida de nuestros bundlers utilizando el método de compresión gzip. Para esto, instalaremos el plugin compression-webpack-plugin:
$ npm i compression-webpack-plugin --save-dev
Ahora modificamos nuestra configuración en el archivo webpack.config.json de la siguiente manera:
// webpack.config.json
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
entry: {
app: './src/all.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].bundle.css',
}),
new OptimizeCSSAssetsPlugin({}),
new BundleAnalyzerPlugin(),
new CompressionPlugin()
]
};
Ejecutamos el comando webpack en modo production.
$ webpack --mode=production
# Hash: f9fa29d7316db86003d5
# Version: webpack 4.43.0
# Time: 3534ms
# Built at: 2020-05-12 12:10:45
# Asset Size Chunks Chunk Names
# app.bundle.css 154 KiB 0 [emitted] app
# app.bundle.css.gz 23.1 KiB [emitted]
# app.bundle.js 97.9 KiB 0 [emitted] app
# app.bundle.js.gz 35.3 KiB [emitted]
# Entrypoint app [big] = app.bundle.css app.bundle.js
Y listo, dentro de nuestra carpeta dist tendremos la versión comprimida de nuestros bundlers, los cuales tendrán la extensión .gz. El archivo comprimido app.bundle.css.gz es 84% más pequeña que la versión sin comprimir, con un tamaño de solo 24 kB. Y el archivo comprimido app.bundle.js.gz es 63% más pequeña que la versión sin comprimir, con un tamaño de solo 36 kB. Lo que representa en promedio de una reducción de arriba del 70% de forma general.
Conclusión
Webpack incluye muchas características más de las que mencionamos en este tutorial, lo mencionado en este tutorial te ayudará a que comprendan la esencia de Webpack y el por que ha sobresalido sobre Grunt y Gulp.
Espero que este tutorial les sirva para comprender los conceptos básicos de Webpack, si ya lo conocías espero que te sirva como referencia y reforces tus conocimientos acerca de Webpack. Si les ha gustado el tutorial valoren el esfuerzo y compartan en sus redes sociales. No duden en comentar dudas, aportes o sugerencias, estaré encantado de responderles.