Webpack es una herramienta Frontend que nos permite empaquetar el código de nuestras aplicaciones, y demás archivos estáticos como: HTML, CSS, javascript y fuentes, y prepararlo para colocarlo en producción.
En otras palabras, es un module bundler que nos facilita el desarrollo de aplicaciones, permitiéndonos manipular de forma eficiente nuestro código y demás archivos necesarios de nuestra aplicación. Finalmente genera la versión de distribución de la manera más optimizada posible.
Webpack nació en el año 2012 y desde ahí se ha convertido en la herramienta de desarrollo más importante para empresas como Meta, Twitter, Paypal y el resto de la comunidad de desarrollo web del mundo.
Es importante que tengas en cuenta que esta herramienta es de una filosofía de trabajo modular; esto indica que debemos dividir nuestro código y elementos estáticos en diferentes módulos para que Webpack los empaquete y genere un resultado final listo para producción.
¿Qué puedes hacer con Webpack?
Con esta herramienta puedes:
- Gestionar las dependencias
- Ejecutar tareas
- Convertir archivos estáticos
- Generar un entorno de desarrollo para hacer pruebas locales de tus aplicaciones
- Cargar diferentes módulos de JavaScript
- Minificar código JavaScript y CSS
- Instalar plugins para extender sus funcionalidades
- Trabajar con preprocesadores CSS y PostCSS
Conceptos básicos de Webpack
Esta herramienta construye un gráfico de dependencias que mapea cada módulo para convertirlo en uno o más módulos según el caso. Antes de la versión 4, se necesitaba crear un archivo de configuración para poder crear un entorno de desarrollo con Webpack.
Entry point
El punto de entrada es uno o más documentos de donde parte el inicio de nuestra aplicación.
Output
El punto de salida es uno o varios documentos que son el resultado del procesamiento de Webpack. Por lo general, es la carpeta dist donde se almacenan los documentos estáticos de nuestra aplicación web lista y optimizada para producción.
Loaders
A través de los loaders podemos manipular y empaquetar ciertas particularidades de nuestro proyecto. Por ejemplo, podemos utilizar un loader para que Webpack comprenda un lenguaje en específico como jsx.
Plugins
A través de los plugins podemos añadir algunas funcionalidades o configuraciones particulares de los loaders.
Modos de Webpack
- Modo de desarrollo: esta herramienta proporciona elementos para poder trabajar más cómodamente en un entorno de desarrollo. Por ejemplo, permite generar un servidor web con la posibilidad de observar los cambios en tiempo real.
- Modo de producción: genera un paquete optimizado para colocar nuestra aplicación en producción.
- Modos de performance: nos permite añadir configuraciones avanzadas para indicar cómo deseamos que se empaquete nuestro proyecto, hacia donde va a almacenarse, como también generar un servidor local con un puerto específico y así ver los cambios en tiempo real en nuestro navegador.
Preparación de un proyecto antes de instalar Webpack
Te voy a indicar unos pasos previos para poder realizar este instructivo. Cuando era muy novato, se me hacía molesto encontrar documentación sobre lo que necesitaba pero que no me proporcionaban un punto de partida.
Entonces, antes de iniciar, te recomiendo hacer estos breves pasos a continuación para poder aprender a utilizar webpack.
Si deseas ir a más profundidad, tengo un artículo en el que explico la manera de configurar un entorno de desarrollo en Windows.
Elementos a considerar antes de iniciar este instructivo
- Todos los comandos de consola son basados en el sistema operativo Linux
- Entiendo que sabes manejar bien el sistema operativo Windows o Mac OS
1. Crear la carpeta del proyecto
Simplemente es crear una carpeta dónde vas a guardar todos los archivos de tu proyecto web. Si estas utilizando una interfaz gráfica, solamente es ubicarte en el lugar de directorio donde deseas crear el proyecto y pum, crearla con clic derecho o en el administrador de carpetas del Sistema Operativo.
Si utilizas una consola el comando es el siguiente: mkdir nombre_carpeta
2. Ubicarte dentro de la carpeta
El comando de consola para navegar por carpetas es el siguiente: cd /nombre_carpeta/nombre_carpeta …
3. Inicializamos un proyecto JavaScript
Ubicados dentro de la carpeta introducimos el siguiente código en la consola: npm init –y
- npm. Es el administrador de paquetes
- init. Es el comando utilizado para inicializar con npm un proyecto JavaScript
- -y. Es un comodín el cual responderá “Sí” a todas las preguntas que se solicitan en el momento de la creación de un proyecto JavaScript. Es algo para ahorrar tiempo, el documento manifiesto del proyecto se puede modificar en cualquier otro momento.
4. Inicializamos un proyecto git
Git es un sistema gestión de versiones muy útil para hacer trazabilidad al avance de desarrollo de un proyecto. Luego, este mismo proyecto se puede subir a un sistema administrador de versiones en la nube como github o gitlab.
Para inicializar un proyecto git, escribimos el siguiente comando en consola: git init
Instalación de Webpack
Ubicados en la carpeta donde deseamos trabajar nuestro proyecto, introducimos el siguiente comando:
npm install webpack webpack-cli –D
- npm. Es el sistema gestor de paquetes que nos proporcionará a Webpack.
- install. Es el comando para instalar webpack.
- webpack. Es el nombre del paquete que estamos requiriendo.
- webpack-cli. Es otro paquete de webpack para que podamos hacer uso de los comandos específicos que solo funcionan para la herramienta.
- -D. Es un comodín con el que le indicamos a npm que instale esta herramienta solo en un entorno de desarrollo. Es decir, estos archivos se omitirán cuando se genere la distribución de producción, pues no se necesitan.
Creación del archivo de configuración webpack.config.js
Este archivo nos va ayudar a establecer la configuración de los diferentes elementos que vamos a utilizar, como los loaders, plugins, entry points, outputs y demás elementos que necesitemos procesar con Webpack.
1. Creamos un archivo en la raíz de nuestro proyecto y lo llamamos webpack.config.js
Con el editor de código que utilicemos creamos un nuevo documento de JavaScript y lo nombramos “webpack.config.js”
2. Requerimos la librería de node llamada “path”
Este módulo ya viene instalado por defecto en node.js y no es necesario requerir una dependencia.
const path = require('path');
3. Creación del módulo de Webpack
Creamos un módulo que vamos a exportar con un objeto que contiene toda la información de la configuración deseada de Webpack.
module.exports = { ...}
4. Creación del entry point, punto de entrada
Dentro del objeto module.exports, creamos el primer parámetro de configuración de webpack que nos permite obtener el archivo de entrada de nuestro proyecto. Esto es muy importante porque debemos de indicarle el elemento de inicio de nuestra aplicación.
entry: './src/index.js',
- ./src/index.js. Es la ruta donde se encuentra nuestro archivo de entrada.
5. Creación del output
El output es el lugar de destino a donde irá nuestro código una vez sea empaquetado por Webpack. Es decir, es la carpeta que contiene los archivos listos para producción de nuestro proyecto.
Creamos un objeto que tendrá las configuraciones que deseamos en la carpeta “dist” que es un diminutivo del nombre “distribution”.
output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' },
- Path: path.resolve(__dirname, ‘dist’). Nos indica el lugar donde se va a guardar nuestro proyecto una vez compilado. Se utiliza el módulo path con el fin de evitar problemas de ejecución de Webpack en el momento de empaquetar los archivos para producción.
Se recomienda utilizar la palabra “dist” porque es un estándar para determinar la carpeta que contiene los archivos de producción del proyecto.
- filename: ‘main.js’. Es el nombre que le asignamos al archivo resultante que contendrá todo nuestro proyecto empaquetado. También se puede utilizar el nombre “bundle.js” aunque se puede colocar el nombre que se desee.
6. Especificamos con qué extensiones vamos a trabajar en el proyecto
Creamos un objeto que se llame resolve y dentro de este creamos un arreglo que contendrá las extensiones de archivo que vamos a utilizar en el proyecto y por ende, vamos a necesitar que Webpack procese.
resolve: { extensions: ['.js'], },
Por ejemplo, le hemos indicado a Webpack que la extensión que vamos a utilizar es JavaScript
Con el comando de consola: npx webpack –mode production –config webpack.config.js
Ejecutamos webpack para que empaquete y prepare nuestro código para producción. Si puedes observar, al utilizar --config webpack.config.js
le estamos indicando a la herramienta que utilice el archivo de configuración que hemos creado de los puntos 1 al 6
El código completo de la configuración inicial de webpack sería el siguiente
const path: require('path');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, resolve: { extensions: ['.js'], }}
Configuración de Babel
Babel es una herramienta que nos permite utilizar las últimas especificaciones del lenguaje JavaScript en nuestros proyectos.
Al configurar Babel en Webpack, podremos utilizar JavaScript de última generación durante el desarrollo con la tranquilidad de que cuando se construya el bundle (o paquete de producción) Webpack transformará el JavaScriptde última generación que hemos utilizado a un JavaScript que puedan interpretar todos los navegadores.
1. Instalamos las dependencias necesarias para poder utilizar Babel en Webpack
npm install babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
- @babel/core. Es el contenido total del recurso babel
- @babel/preset-env. Nos permitirá utilizar el JavaScript más moderno y convertirlo a un lenguaje que puedan interpretar todos los navegadores
- @babel/plugin-transform-runtime. Como utilizamos funciones asíncronas en nuestro proyecto, es necesario adicionar esta funcionalidad.
2. Creamos una configuración especial para Babel
Creamos un archivo llamado “.babelrc” en la raíz del proyecto.
El punto inicial se utiliza para indicar que es un archivo oculto. Es decir, un archivo que no es visible para los usuarios.
2.1 Creamos un objeto donde especificamos las configuraciones de Babel
Este archivo de configuración es para que Babel entienda cómo va a trabajar con nuestro JavaScript.
{ “presets”: [ “@babel/preset-env” ], “plugins”: [ “@babel/plugin-transform-runtime” ]}
3. Agregamos Babel a nuestro archivo de configuración de Webpack
Creamos un objeto llamado module que servirá para agregar todas las configuraciones de babel dentro de un objeto.
module: { …}
3.1 Agregamos las reglas para el uso de babel
Dentro del objeto module, agregamos un arreglo que contendrá un objeto con las reglas de uso.
rules: [ { … }]
3.2 Realizar un test
Este test nos permitirá saber qué tipo de extensiones vamos a utilizar. Esto se hace con expresiones regulares. Este test se ubica dentro del objeto creado en el arreglo module.
test: /\.m?Js$/,
- /\.m?Js$/,. Esta es una expresión regular que indica que Webpack utilice cualquier extensión que inicie por “mjs” o “js”. La extensión “mjs” es la de los módulos.
3.3 Excluir los módulos de node
Esto nos permitirá evitar conflictos en la ejecución de nuestro proyecto.
Exclude: /node_modules/,
3.4 Indicamos que utilice Babel
Creamos un objeto llamado use dentro del objeto del arreglo rules e indicamos que utilice el loader de Babel.
use: { loader: 'babel-loader'}
El código resultante hasta ahora sería el siguiente:
const path: require('path');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } ] }}
HTML en Webpack
Para que esta herramienta pueda utilizar y procesar HTML debemos hacer lo siguiente
1. Instalar el plugin de html-webpack-plugin
npm install html-webpack-plugin –D
2. Configuramos HTML en nuestro archive webpack.config.js
2.1 Requerimos el recurso
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
2.2 Agregamos la sección de plugins en webpack.config.js
Después de la sección module, agregamos la nueva sección plugins
Plugins: [ …]
2.3 Configuramos el plugin HTML dentro de la sección plugins
Generamos un nuevo objeto que contendrá todas las configuraciones del plugin HTML
new HtmlWebpackPlugin({ …})
2.4 Insertamos los elementos del plugin
Dentro del objeto creado en el punto 2.3 escribimos:
inject: true,
2.5 agregamos el template a la configuración
A Webpack debemos informarle dónde está el recurso HTML que vamos a utilizar en el proyecto. Para este manual se haría de la siguiente forma.
Dentro del objeto creado en el punto 2.3 agregamos el siguiente código:
template: './public/index.html',
2.6 Indicamos el resultado de la preparación del archivo HTML
Dentro del objeto creado en el punto 2.3 agregamos la siguiente instrucción.
filename: './index.html'
Se puede agregar el nombre que deseamos, sin embargo, por convención es importante manejar el estándar “index.html”.
Entonces realizando los puntos 2.1 hasta 2.6, Webpack tomará nuestro template, lo procesará y lo llevará optimizado a la carpeta de “dist” con el nombre de index.html.
Aviso importante
Como Webpack integra el template HTML en JavaScript, no es necesario importar el archivo index.js (o cualquiera sea el nombre) dentro del documento HTML.
3. En la consola comprobamos el funcionamiento de todas las configuraciones realizadas hasta ahora incluyendo HTML.
Crearemos un script para ejecutar el build de Webpack con características de producción.
3.1 Generamos el script en package.json
En el archivo package.json, en su sección de scripts, agregamos el siguiente código:
"build": "webpack --mode production"
3.2 Ejecutamos el script para crear un paquete de nuestro proyecto en producción
Escribimos el siguiente código en nuestra consola y lo ejecutamos
npm run build
Si todo está OK, debe aparecer la consola de la siguiente manera.
Como vemos, se ha creado una carpeta llamada “dist” que contiene nuestro proyecto optimizado para colocarlo en producción.
3.3 Crearemos un script para empaquetar nuestro proyecto pero en modo development
En el archivo package.json, en su sección de scripts, agregamos el siguiente código:
"dev": "webpack --mode development"
3.4 Ejecutamos el script para crear un paquete de nuestro proyecto en producción
Escribimos el siguiente código en nuestra consola y lo ejecutamos
npm run dev
CSS y Webpack
Sé que este ha sido uno de los momentos que más has estado esperando; pues como desarrolladores Frontend, pasamos horas y horas dándole sentido visual a nuestros proyectos.
Esta herramienta de desarrollo la puedes configurar completamente para trabajar con CSS; incluso, puedes trabajar con preprocesadores como Stylus, SASS, LESS o también con postCSS.
1. Configuración de CSS en Webpack
1.1 Instalación de dependencias
npm install mini-css-extract-plugin css-loader -D
1.2 Configuración del archivo webpack.config.js
1.2.1 Importamos el plugin para poder trabajar con CSS
Declaramos una variable constante para obtener el recurso
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
1.2.3 Creamos las reglas necesarias para que Webpack pueda reconocer nuestro CSS
Dentro del arreglo de rules del objeto module, creamos un nuevo objeto para agregar las reglas CSS.
module: {rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: 'babel-loader' }, { … } ]}
1.2.4 Creamos el test dentro del nuevo objeto para que Webpack reconozca los archivos CSS a través de una expresión regular.
test: /\.css$/i,
1.2.5 Creamos el parámetro “use” para indicarle a Webpack que utilice el loader de CSS
use: [MiniCssExtractPlugin.loader, 'css-loader'],
1.2.6 Dentro del apartado de plugins, creamos una nueva instancia para que Webpack reconozca el plugin CSS
new MiniCssExtractPlugin()
Ahora, podemos empaquetar nuestra aplicación en modo de desarrollo utilizando npm run dev
IMPORTANTE
- En el archivo de HTML no es necesario invocar el archivo CSS
- El CSS se debe invocar desde el archivo index.js de la siguiente manera:
import './styles/main.css';
Obvio, la ruta cambia según tu orden de carpetas.
2. Preprocesadores y Webpack
En esta oportunidad vamos a trabajar con el preprocesador Stylus, sin embargo, la configuración es muy parecida para los preprocesadores SASS y LESS.
2.1 Instalación del loader de Stylus
npm install stylus stylus-loader –D
2.2 En el archivo webpack.config.js, creamos la regla para que Wepback reconozca el lenguaje Stylus
Esto lo hacemos en la expresión regular donde decimos que reconozca CSS.
test: /\.css|.styl$/i,
2.3 En el archivo webpack.config.js, agregamos el loader en el arreglo de use del objeto que se utiliza para manipular CSS
use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader'],
2.4 Importamos el archivo de Stylus que utilizamos para escribir el código .styl en el archivo index.js. Así como cuando importamos el archivo CSS
import './styles/main.styl';
Hasta este punto el código de configuración webpack.config.js debería estar así.
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin() ]}
Copia de archivos con Webpack
Para copiar archivos desde la carpeta src hacia la carpeta de distribución sigue los siguientes pasos.
1. Instalar del plugin copy-webpack-plugin
npm install copy-webpack-plugin –D
2. Configurar los elementos que van a ser copiados a través de Webpack
2.1 Creamos la variable constante que traerá el plugin a nuestro documento de configuración.
const CopyPlugin = require(‘copy-webpack-plugin’);
2.2 Creamos una instancia del plugin en la sección plugins en el documento de configuración
new CopyPlugin({})
2.3 Dentro de esta instancia generamos un objeto dentro de un arreglo llamado patterns que tendrá las rutas de los archivos
patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ]
Nota: cambia las rutas según tus necesidades.
3. referenciación de imágenes
Como el destino final de las imágenes es la carpeta “dist”, la manera correcta de referenciar las imágenes es agregando en la etiqueta que utiliza ese archivo, la ruta final definida en el punto 2.3. Por ejemplo:
<img src =”assets/images/imagen.jpg” />
Así quedaría el archivo de configuración con esta nueva actualización:
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');const CopyPlugin = require('copy-webpack-plugin');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin(), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ] }) ]}
Loaders de imágenes
Anteriormente observamos la posibilidad de copiar, o mejor dicho, trasladar archivos desde la carpeta src del proyecto hacia la carpeta dist. En esta oportunidad, vamos a darle tratamiento de nuestras imágenes haciendo un import de las mismas, llamándolas como variables y generándolas directamente en nuestro proyecto.
1. Configuración del archivo webpack.config.js
1.1 Agregamos la herramienta assets module nativa de Webpack
Dentro del arreglo rules del objeto module, agregamos la regla
{ test: /\.png/, // indicamos el listado de archivos a los cuales vamos a dar tratamiento type: 'asset/resource', // Permite la importación del recurso en el template }
1.2 Cambiamos la manera en la que webpack nombra y ubica el recurso de imagen
En el objeto output, después de filename: 'main.js
Colocamos el siguiente código:
assetModuleFilename: 'assets/images/[hash][ext][query]'
Con esto, las imágenes se guardarán en la carpeta assets/images y lo hará con el código hash y su extensión.
2. Modificación de la manera en que se llama el recurso en el template
La imagen puede ser ahora llamada a modo de importación en el archivo template.js
2.1 Importación o llamado de los recursos de imágenes
import instagram from '../assets/images/instagram.png';import twitter from '../assets/images/twitter.png';import github from '../assets/images/github.png';
2.2 Llamado de las imágenes en la etiqueta <img/>
<div class="card_social"> <a href="https://twitter.com/gndx"> <img src="${twitter}" /> </a> <a href="https://github.com/gndx"> <img src="${github}" /> </a> <a href="https://instagram.com/gndx"> <img src="${instagram}" /> </a></div>
Una vez terminada la configuración, cuando el navegador haga render de las vistas del proyecto las imágenes serán importadas y se les asignará un código hash.
Así, el archivo de configuración de Webpack quedaría así:
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');const CopyPlugin = require('copy-webpack-plugin');const { resourceUsage } = require('process');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js', assetModuleFilename: 'assets/images/[hash][ext][query]' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], }, { test: /\.png/, // indicamos el listado de archivos a los cuales vamos a dar tratamiento type: 'asset/resource', // Permite la importación del recurso en el template } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin(), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ] }) ]}
Loaders de fuentes
Configurar las fuentes en Webpack es mucho más eficiente que llamarlas desde un CDN. Por eso, es importante incorporarlas a nuestro proyecto y Webpack nos proporciona la manera de hacerlo.
Desde Google Fonts puedes descargar gran cantidad de fuentes; sin embargo, no ofrece la posibilidad de descargarlas con la extensión de archivo .woff, este tipo de archivo ofrece una fuente optimizada para ser utilizada en la web.
Con esta utilidad podrás obtener las fuentes optimizadas para ser utilizadas en tus proyectos.
1. Instalación de los recursos necesarios
Para que podamos utilizar las fuentes, debemos hacer que se copien los archivos de fuentes desde la carpeta src hacia dist las fuentes. Entonces, se debe instalar dos recursos: uno para leerlos y otro para moverlos según el caso.
Instalación de los recursos url-loader y file-loader
npm install url-loader file-loader –D
2 Configuración del archivo config.webpack.js
Dentro del arreglo rules del objeto module, agregamos las siguientes configuraciones.
{ test: /\.(woff|woff2)$/, // Expresión regular para que utilice las extensiones de archivo use: { loader: 'url-loader', options: { limit: 10000, mimetype: "application/font-woff", // "Especificamos de que tipo de archivo se trata" name: "[name].[ext]", // Indicamos que respete el nombre y la extensión que tiene la fuente outputPath: "./assets/fonts", // Indicamos hacia donde se va a dirigir el recurso publicPath: "./assets/fonts", // También es necesario asignar un public path esModule: false } } }
2. Agregamos las propiedades CSS para la utilización de las fuentes en nuestro proyecto
@font-face{ font-family: 'Ubuntu'; src: url('../assets/fonts/ubuntu-regular.woff2') format('woff2'), url('../assets/fonts/ubuntu-regular.woff') format('woff'); font-weight: 400; /* 400 es normal */ font-style: normal;}
Hasta el momento, el documento de configuración está así:
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');const CopyPlugin = require('copy-webpack-plugin');const { resourceUsage } = require('process');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js', assetModuleFilename: 'assets/images/[hash][ext][query]' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], }, { test: /\.png/, // indicamos el listado de archivos a los cuales vamos a dar tratamiento type: 'asset/resource', // Permite la importación del recurso en el template }, { test: /\.(woff|woff2)$/, // Expresión regular para que utilice las extensiones de archivo use: { loader: 'url-loader', options: { limit: 10000, mimetype: "application/font-woff", // "Especificamos de que tipo de archivo se trata" name: "[name].[ext]", // Indicamos que respete el nombre y la extensión que tiene la fuente outputPath: "./assets/fonts", // Indicamos hacia donde se va a dirigir el recurso publicPath: "./assets/fonts", // También es necesario asignar un public path esModule: false } } } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin(), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ] }) ]}
Optimización de un proyecto web
En este apartado te explicaré la forma de optimizar los recursos que intervienen en el funcionamiento de un proyecto web. Esto, con el fin de que cargue rápido y funcione de forma eficiente para los usuarios finales.
¿Qué se optimizará? Se optimizarán hashes y se realizarán tareas de compresión y minificación de archivos.
1. Minimizar JavaScript y CSS
1.1 Instalación de las dependencias
npm install css-minimizer-webpack-plugin terser-webpack-plugin -D
1.2 Requerimos los plugins instalados en el punto 1.1 en nuestro archive de configuración de Webpack
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');const TerserPlugin = require('terser-webpack-plugin');
1.3 Creamos un nuevo objeto llamado “optimization” justo debajo del arreglo “plugins” en webpack.config.js
En este objeto se colocarán todas las configuraciones de optimización.
optimization: { minimize: true, minimizer: [ new CssMinimizerPlugin(), new TerserPlugin(), ] }
2. Optimización Hash
Esta optimización es recomendada si deseamos saber si ha cambiado la versión de los archivos en el momento de realizar un nuevo build (empaquetado del proyecto). Entonces, según el documento de configuración que se ha venido trabajando, cambiaremos la estructura del nombre de: “main.js”, también el nombre de nuestras fuentes de texto y el archivo CSS.
2.1 Cambio del filename
En el output de webpack, cambiamos la propiedad del filename por la siguiente
filename: '[name].[contenthash].js',
2.2 Cambio de nombre a código hash de las fuentes de texto
Cambiamos la propiedad name del objeto options ubicado en el objeto use de la configuración de las fuentes en webpack.config.js
name: “[name].[contenthash].[ext]”,
2.3 Cambio de nombre para el archivo CSS
Pasamos como parámetro una configuración en el objeto MiniCssExtractPlugin del arreglo plugins.
new MiniCssExtractPlugin({ filename: 'assets/[name].[contenthash].css' }),
Hasta este punto, el archivo de configuración luce así:
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');const CopyPlugin = require('copy-webpack-plugin');const { resourceUsage } = require('process');const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');const TerserPlugin = require('terser-webpack-plugin');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[contenthash].js', assetModuleFilename: 'assets/images/[hash][ext][query]' }, resolve: { extensions: ['.js'], }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], }, { test: /\.png/, // indicamos el listado de archivos a los cuales vamos a dar tratamiento type: 'asset/resource', // Permite la importación del recurso en el template }, { test: /\.(woff|woff2)$/, // Expresión regular para que utilice las extensiones de archivo use: { loader: 'url-loader', options: { limit: 10000, mimetype: "application/font-woff", // "Especificamos de que tipo de archivo se trata" name: "[name].[contenthash].[ext]", // Indicamos que respete el nombre y la extensión que tiene la fuente outputPath: "./assets/fonts", // Indicamos hacia donde se va a dirigir el recurso publicPath: "./assets/fonts", // También es necesario asignar un public path esModule: false } } } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin({ filename: 'assets/[name].[contenthash].css' }), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ] }) ], optimization: { minimize: true, minimizer: [ new CssMinimizerPlugin(), new TerserPlugin(), ] }}
Webpack Alias
Webpack permite generar alias para ubicar más fácilmente los archivos de dependencias de nuestros proyectos.
Por ejemplo en el archivo index.js de la carpeta src, estamos requiriendo otros archivos ubicados en diferentes carpetas. Algunas veces, esta búsqueda se hace compleja y las rutas pueden quizá ser tan complejas que las olvidamos o no sabemos cómo acceder a ellas.
Entonces, generando alias, solucionamos este problema.
1. Configuración de alias en Webpack
Dentro del objeto resolve, creamos un objeto llamado alias que contendrá las configuraciones que necesitamos.
Alias: {}
2 Identificación de carpetas
Luego, debemos identificar las carpetas que estamos utilizando en el desarrollo del proyecto dentro de la carpeta src. Estas carpetas son las que vamos a configurar dentro del objeto alias, realizado en el punto 1.
3. Configuración de los alias
Dentro del objeto alias creado en el punto 1, agregamos el siguiente código:
'@utils': path.resolve(__dirname, 'src/utils/'),'@templates': path.resolve(__dirname, 'src/templates/'),'@styles': path.resolve(__dirname, 'src/styles/'),'@images': path.resolve(__dirname, 'src/assets/images/')
- ‘@utils‘… Es el alias asignado a la resolución de la dirección de donde se encuentra el recurso.
Con esto, podemos utilizar los alias generados en las rutas que se referencian en nuestro proyecto.
Ejemplo sin alias
import Template from './templates/Template.js';import './styles/main.css';import './styles/main.styl';import instagram from '../assets/images/instagram.png';import twitter from '../assets/images/twitter.png';import github from '../assets/images/github.png';
Ejemplo con alias
import Template from '@templates/Template.js';import '@styles/main.css';import '@styles/main.styl';import instagram from '@images/instagram.png';import twitter from '@images/twitter.png';import github from '@images/github.png';
Finalmente, el archivo de configuración de Webpack quedaría así:
const path = require('path');const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require('mini-css-extract-plugin');const CopyPlugin = require('copy-webpack-plugin');const { resourceUsage } = require('process');const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');const TerserPlugin = require('terser-webpack-plugin');module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[contenthash].js', assetModuleFilename: 'assets/images/[hash][ext][query]' }, resolve: { extensions: ['.js'], alias: { '@utils': path.resolve(__dirname, 'src/utils/'), '@templates': path.resolve(__dirname, 'src/templates/'), '@styles': path.resolve(__dirname, 'src/styles/'), '@images': path.resolve(__dirname, 'src/assets/images/') } }, module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /\.css|.styl$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'stylus-loader' ], }, { test: /\.png/, // indicamos el listado de archivos a los cuales vamos a dar tratamiento type: 'asset/resource', // Permite la importación del recurso en el template }, { test: /\.(woff|woff2)$/, // Expresión regular para que utilice las extensiones de archivo use: { loader: 'url-loader', options: { limit: 10000, mimetype: "application/font-woff", // "Especificamos de que tipo de archivo se trata" name: "[name].[contenthash].[ext]", // Indicamos que respete el nombre y la extensión que tiene la fuente outputPath: "./assets/fonts", // Indicamos hacia donde se va a dirigir el recurso publicPath: "../assets/fonts", // También es necesario asignar un public path esModule: false } } } ] }, plugins: [ new HtmlWebpackPlugin({ inject: true, template: './public/index.html', filename: './index.html' }), new MiniCssExtractPlugin({ filename: 'assets/[name].[contenthash].css' }), new CopyPlugin({ patterns: [ { from: path.resolve(__dirname, "src", "assets/images"), to: "assets/images" } ] }) ], optimization: { minimize: true, minimizer: [ new CssMinimizerPlugin(), new TerserPlugin(), ] }}