El desarrollo front-end ha cambiado a un enfoque modular, mejorando la encapsulación y la estructura de las bases de código. Las herramientas se convirtieron en una parte fundamental de cualquier proyecto y, en este momento, hay muchas opciones posibles.
Webpack ha ganado popularidad en los últimos años debido a su potencia y escalabilidad, pero algunos desarrolladores encontraron su proceso de configuración confuso y difícil de adoptar.
Iremos paso a paso desde un archivo de configuración vacío hasta una configuración simple pero completa para agrupar un proyecto. Este artículo asume una comprensión básica de la notación CommonJS y cómo funcionan los módulos.
Conceptos
A diferencia de la mayoría de los paquetes que existen, la motivación detrás de Webpack es recopilar todas sus dependencias (no solo el código, sino también otros activos) y generar un gráfico de dependencia.
Al principio, puede parecer extraño ver que un archivo `.js` requiere una hoja de estilo, o una hoja de estilo que recupera una imagen modificada como si fuera un módulo, pero esto le permite a Webpack comprender lo que está incluido en su paquete y lo ayuda a transformar y optimizar ellos.
Instalar en pc
Primero agreguemos los paquetes iniciales que vamos a usar:
npm install webpack webpack-dev-server --save-dev
A continuación, creamos un archivo `webpack.config.js` en la raíz de nuestro proyecto y agregamos dos scripts a nuestros archivos `package.json` tanto para el desarrollo local como para la versión de producción.
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
}
Los comandos de Webpack recogerán el archivo de configuración que acabamos de crear a menos que indiquemos otra acción.
Entrada
Hay muchas formas de especificar nuestro “punto de entrada”, que será la raíz de nuestro gráfico de dependencias.
La más fácil es pasar una cadena:
var baseConfig = {
entry: './src/index.js'
};
También podríamos pasar un objeto en caso de que necesitemos más de una entrada en el futuro.
var baseConfig = {
entry: {
main: './src/index.js'
}
};
Recomiendo el último ya que se escalará mejor a medida que crezca su proyecto.
Producción
La salida en Webpack es un objeto que contiene la ruta donde irán nuestros paquetes y activos, así como el nombre que adoptarán las entradas.
var path = require('path');
var baseConfig = {
entry: {
main: './src/index.js'
},
output: {
filename: 'main.js',
path: path.resolve('./build')
}
};
// export configuration
module.exports = baseConfig;
Si estás definiendo el entrada con un objeto, en lugar de codificar el nombre del archivo de salida con una cadena, puede hacer lo siguiente:
output: {
filename: '[name].js',
path: path.resolve('./build')
}
De esta manera, cuando se agreguen nuevas entradas, Webpack recogerá su clave para formar el nombre del archivo.
Con solo este pequeño conjunto de configuraciones, ya podemos ejecutar un servidor y desarrollar localmente con npm start
o npm run build
para agrupar nuestro código para el lanzamiento. Al conocer las dependencias del proyecto, webpack-dev-server las observará y recargará el sitio cuando detecte que una de ellas ha cambiado.
Cargadores
El objetivo de Webpack es manejar todas nuestras dependencias.
// index.js file
import helpers from '/helpers/main.js';
// Hey Webpack! I will need these styles:
import 'main.css';
¿Que es eso? ¿Necesita una hoja de estilo en JavaScript? ¡Sí! Pero los empaquetadores solo están preparados para manejar dependencias de JavaScript listas para usar. Aquí es donde hacen su entrada los “cargadores”.
Los cargadores proporcionan una manera fácil de interceptar nuestras dependencias y preprocesarlas antes de que se empaqueten.
var baseConfig = {
// ...
module: {
rules: [
{
test: /* RegEx */,
use: [
{
loader: /* loader name */,
query: /* optional config object */
}
]
}
]
}
};
Para que los cargadores funcionen, necesitamos una expresión regular para identificar los archivos que queremos modificar y una cadena o matriz con los cargadores que queremos usar.
Estilos
Para permitir que Webpack procese nuestros estilos cuando sea necesario, vamos a instalar CSS y estilo cargadores
npm install --save-dev css-loader style-loader
El cargador css interpretará los estilos como dependencias y el cargador de estilo incluirá automáticamente un <style>
etiqueta con ellos en la página cuando se carga el paquete.
var baseConfig = {
entry: {
main: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve('./build')
},
module: {
rules: [
{
test: /.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' }
]
}
]
}
};
En este ejemplo, main.css
pasará primero a través cargador css y luego cargador de estilo.
preprocesadores
Agregar soporte para LESS o cualquier otro preprocesador es tan simple como instalar el cargador correspondiente y agregarlo a la regla.
rules: [
{
test: /.less$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'less-loader' }
]
}
]
Transpilar
Los cargadores también pueden transformar JavaScript. Un ejemplo sería usar un cargador de Babel para transpilar nuestros scripts.
rules: [
{
test: /.js$/,
use: [
{ loader: 'babel-loader' }
]
}
]
Imágenes
Webpack tiene una gran característica donde puede detectar url()
declaraciones dentro de las hojas de estilo y permitir que los cargadores apliquen cambios al archivo de imagen y la URL misma.
// index.less file
@import 'less/vars';
body {
background-color: @background-color;
color: @text-color;
}
.logo {
background-image: url('./images/logo.svg');
}
Al agregar una regla, podríamos aplicar el cargador de archivos para simplemente copiar el archivo o usar el cargador de URL, el último inserta la imagen como una cadena base64 a menos que exceda un límite de bytes, en cuyo caso reemplazará la declaración de URL con una ruta relativa y copiará el archivo en la ubicación de salida para nosotros.
{
test: /.svg$/,
use: [
{
loader: 'url-loader',
query: { limit : 10000 }
}
]
}
Los cargadores se pueden configurar pasando un query
objeto con opciones, como aquí, donde estamos configurando el cargador para alinear el archivo a menos que supere los 10 Kb de tamaño.
Administrando nuestro proceso de compilación de esta manera, solo incluiremos los recursos necesarios en lugar de mover una carpeta de activos hipotéticos con toneladas de archivos que podrían o no usarse en nuestro proyecto.
Si usa React o una biblioteca similar, puede requerir el .svg
archivo en su componente con el cargador-en-línea-svg.
Complementos
Webpack contiene comportamientos predeterminados para agrupar la mayoría de los tipos de recursos. Cuando los cargadores no son suficientes, podemos usar complementos para modificar o agregar capacidades a Webpack.
Por ejemplo, Webpack incluye de forma predeterminada nuestros estilos dentro de nuestro paquete, pero podemos modificar esto introduciendo un complemento.
Extracción de activos
Un uso común para un complemento es extraer la hoja de estilo generada y cargarla como lo hacemos normalmente usando un <link>
etiqueta.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var lessRules = {
use: [
{ loader: 'css-loader' },
{ loader: 'less-loader' }
]
};
var baseConfig = {
// ...
module: {
rules: [
// ...
{ test: /.less$/, use: ExtractTextPlugin.extract(lessRules) }
]
},
plugins: [
new ExtractTextPlugin('main.css')
]
};
Generar un archivo `index.html`
Cuando creamos aplicaciones de una sola página, generalmente necesitamos una .html
archivo para servirlo.
HtmlWebpackPlugin crea automáticamente un archivo `index.html` y agrega etiquetas de script para cada paquete resultante. También es compatible con la sintaxis de plantillas y es altamente configurable.
var HTMLWebpackPlugin = require('html-webpack-plugin');
var baseConfig = {
// ...
plugins: [
new HTMLWebpackPlugin()
]
};
Edificio para Producción
Definir el entorno
Muchas bibliotecas introducen advertencias que son útiles durante el tiempo de desarrollo pero que no tienen uso en nuestro paquete de producción y aumentan su tamaño.
Webpack viene con un complemento incorporado para establecer constantes globales dentro de su paquete.
var ENV = process.env.NODE_ENV;
var baseConfig = {
// ...
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(ENV)
})
]
};
Ahora necesitamos especificar el entorno en nuestros comandos:
"scripts": {
"start": "NODE_ENV=development webpack-dev-server",
"build": "NODE_ENV=production webpack"
}
process.env.NODE_ENV
será reemplazado por una cadena, lo que permitirá a los compresores eliminar ramas de código de desarrollo inalcanzables.
Esto es realmente útil para introducir advertencias en su base de código para su equipo y no llegarán a producción.
if (process.env.NODE_ENV === 'development') {
console.warn('This warning will dissapear on production build!');
}
Apresamiento
En producción, necesitamos dar a los usuarios el producto más rápido posible. Al minimizar nuestro código con la eliminación de caracteres innecesarios, esto reduce el tamaño de nuestro paquete y mejora los tiempos de carga.
Una de las herramientas más populares para hacer esto es UglifyJS, y Webpack viene con un complemento incorporado para pasar nuestro código a través de él.
// webpack.config.js file
var ENV = process.env.NODE_ENV;
var baseConfig = {
// ...
plugins: []
};
if (ENV === 'production') {
baseConfig.plugins.push(new webpack.optimize.UglifyJsPlugin());
}
Envolver
Los archivos de configuración de Webpack son increíblemente útiles y la complejidad del archivo dependerá de sus necesidades. Tenga cuidado de organizarlos bien, ya que pueden volverse más difíciles de domesticar a medida que crece su proyecto.
En este artículo, comenzamos con un archivo de configuración en blanco y terminamos con una configuración básica que le permitiría desarrollar localmente y lanzar código de producción. Hay más para explorar en Webpack, pero estas partes y conceptos clave pueden ayudarlo a familiarizarse más con él.
Si desea profundizar, le recomiendo la documentación oficial de Webpack, que se actualizó y mejoró para su segundo gran lanzamiento.