馃憠 Ver todas las notas
Webpack es un module bundler, su tarea es analizar el c贸digo de nuestra aplicaci贸n, detectar los diferentes m贸dulos que el mismo importa/exporta, aplicar (opcionalmente) las transformaciones necesarias y empaquetar todo el c贸digo en un 煤nico archivo .js
y referenciarlo en el index.html
, para que este pueda ser ejecutado en los browsers luego.
Uno de los problemas que resuelve Webpack entonces, es la necesidad que ten铆amos previamente de linkear todos los scripts de librer铆as y m贸dulos que utiliz谩ramos en el index.html
, en el orden correcto.
Los problemas que generaba esto eran:
- dependencia de servidores de CDN (librer铆as)
- problemas para el versionado: si queremos actualizar alguna librer铆a, tenemos que modificar manualmente los n煤meros de versiones en el
src
, lo que es poco pr谩ctico y propenso a errores - cargar los scrips en el orden incorrecto (si tienen dependencias entre si)
<!-- Linkeando scripts como antes -->
<body>
...
<script src="libs/react.min.js"></script>
<script src="src/admin.js"></script>
<script src="src/api.js.js"></script>
<script src="src/auth.js"></script>
</body>
<!-- Con Webpack -->
<body>
...
<script src="dist/bundle.js"></script>
</body>
Aparte de resolver el problema del bundling, Webpack permite, a trav茅s de diferentes plugins y loaders, aplicar diferentes transformaciones (ej: transpilar TS, o c贸digo ES6+, agregar Babel, etc) y optimizaciones a nuestro c贸digo (ej: code splitting, image opt, etc).
Por defecto, Webpack s贸lo puede analizar y procesar los archivos .js
y .json
de nuestro c贸digo. Probablemente necesitemos incluir estilos (CSS) e im谩genes. Es por este motivo que existen los loaders, que le permiten a Webpack procesar m谩s tipos de archivos, para realizar diferentes transformaciones, optimizaciones e incluirlos en el bundle final.
Para cada loader, tenemos que especificar sobre qu茅 archivos se va a aplicar (podemos usar regex).
Los loaders se instalan a trav茅s de npm
, por ejemplo, para procesar SVGs y CSS
npm i -D svg-inline-loader css-loader
Si adem谩s queremos inyectar los estilos directamente en el DOM, podemos usar style-loader
npm i -D style-loader
A diferencia de los loaders, que se utilizan para procesar y transformar archivos mientras generamos el bundle, los plugins le permiten a Webpack ejecutar ciertas tareas despu茅s de que el bundle fue creado. Por ejemplo, HtmlWebpackPlugin
: genera un index.html
, lo coloca en /dist
(o en cualquier otro destino que definamos en output
), agreg谩ndole un <script>
tag que referencia al bundle creado. Otro plugin 煤til es EnvironmentPlugin
, que nos permite configurar el entorno de producci贸n para el deployment.
Para agregar plugins, debemos instalarlos (al igual que los loaders) y setearlos en la propiedad plugins
de la config
npm i -D html-webpack-plugin
// webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
module: {
rules: [ ... ]
},
output: { ... },
plugins: [
new HtmlWebpackPlugin(),
new webpack.EnvironmentPlugin({
'NODE_ENV': 'production'
})
]
}
El Hot Module Replacement/Reloading permite agilizar el proceso de desarrollo, al dejarnos ver los cambios de forma instant谩nea en el browser, sin necesidad de refrescar el mismo. El mismo s贸lo estar谩 disponible en el entorno de desarrollo, no as铆 en producci贸n.
Instalar Webpack y su CLI como dependencias de desarrollo en el proyecto:
npm i -D webpack webpack-cli
Crear el archivo webpack.config.js
para guardar las opciones de configuraci贸n.
// webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.svg$/, // aplicar esta transformaci贸n a todos los archivos .svg
use: 'svg-inline-loader' // loader que vamos a usar
},
{
test: /\.css$/, // aplicar esta transformaci贸n a todos los archivos .css
use: [ 'style-loader', 'css-loader' ] // en este caso usamos 2 loaders, por eso el array. El orden importa, webpack los procesa en orden inverso
}
]
}
}
En este archivo de config deberemos indicar cosas como:
- entry point de nuestra app (definido en
entry
) - transformaciones que querramos aplicar (definidas en las
rules
dentro demodule
) - destino, con la ubicaci贸n del archivo empaquetado (definido en
output
)
Agregando el babel-loader
para transpilar JS ES6+
npm i -D babel-loader
// webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.svg$/,
use: 'svg-inline-loader'
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
{
test: /\.(js)$/, // aplicar esta transformaci贸n a todos los archivos .js
use: 'babel-loader'
}
]
}
}
Finalmente, para agregar el destino, el output
, que es un objeto con las siguientes propiedades
output: {
path: ... // ubicaci贸n de /dist, el directorio donde se va a ubicar el bundle
filename: ... // nombre del bundle
}
// webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.svg$/,
use: 'svg-inline-loader'
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
{
test: /\.(js)$/, // aplicar esta transformaci贸n a todos los archivos .js
use: 'babel-loader'
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.bundle.js`
}
}
- Webpack analiza el archivo definido como entry point
- Detecta y examina todos los imports/exports del mismo (o
requires
, si estamos usando CommonJS) y genera un dependency graph, para saber qu茅 m贸dulos dependen de cu谩les otros y en qu茅 orden debe insertarlos en el bundle final - Comienza a crear el bundle y a medida que va agregando los scripts, aplica las transformaciones definidas en la config y agrega el output correspondiente
- Finalmente ubica el bundle final seg煤n
output
definido en la config
Podemos realizar el proceso de preparar nuestro bundle para producci贸n (setear el NODE_ENV
, minificar el c贸digo, etc) manualmente, en el caso de que querramos optimizar algo espec铆fico. Pero para simplificar y ahorrar tiempo, podemos usar el mode
de la config y setearlo en production, que va a setear ciertos par谩metros por default (como los mencionados antes).
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
module: {
rules: [ ... ]
},
output: { ... },
plugins: [
new HtmlWebpackPlugin()
],
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development'
}
El mode development de webpack deshabilita las optimizaciones mencionadas y activa el HMR para desarrollar localmente.
El DevServer nos permite levantar un servidor local de desarrollo y carga los archivos en memoria, evit谩ndonos esperar a que se complete el build cada vez que guardamos cambios, para poder ver los mismos en el browser. Este m贸dulo adem谩s es el que incluye el HMR (live reloading). Para usarlo, lo instalamos con
npm i -D webpack-dev-server
En nuestro package.json
, agregamos los scripts de build (bundle optimizado para producci贸n) y dev (este 煤ltimo levanta un server local con HMR)
"scripts": {
"build": "NODE_ENV='production' webpack",
"dev": "webpack serve"
}
y luego lo corremos con npm run build
.