¡Buen dia amigos!
Les presento una traducción del artículo "Webpack: Una suave introducción" de Tyler McGinnis.
Antes de explorar una nueva tecnología, hágase dos preguntas:
- ¿Por qué se necesita esta herramienta?
- ¿Qué tareas realiza?
Si no puede responder estas preguntas, es posible que no necesite la tecnología que está estudiando. Intentemos responder estas preguntas en relación con Webpack.
¿Por qué necesitas un paquete web?
Webpack es un constructor de módulos. Analiza los módulos de la aplicación, crea un gráfico de dependencia y luego ensambla los módulos en el orden correcto en uno o más paquetes, que pueden ser referenciados por el archivo "index.html".
App.js -> |
Dashboard.js -> | Bundler | -> bundle.js
About.js -> |
¿Qué problemas resuelve webpack?
Por lo general, al crear una aplicación JavaScript, el código se divide en varias partes (módulos). Luego, en el archivo "index.html", debe especificar un enlace a cada secuencia de comandos.
<body>
...
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="libs/react.min.js"></script>
<script src='src/admin.js'></script>
<script src='src/dashboard.js'></script>
<script src='src/api.js'></script>
<script src='src/auth.js'></script>
<script src='src/rickastley.js'></script>
</body>
Esto no solo es tedioso sino también propenso a errores. Es importante no solo no olvidarse de ningún guión, sino también organizarlos en el orden correcto. Si carga un script que depende de React antes de cargar React, su aplicación se romperá. Webpack resuelve estos problemas. No hay necesidad de preocuparse por incluir todos los scripts en secuencia.
<body>
...
<script src='dist/bundle.js'></script>
</body>
Como pronto aprenderemos, la recopilación de módulos es solo un aspecto del funcionamiento de un paquete web. Si es necesario, puede forzar al paquete web a realizar algunas transformaciones de módulos antes de agregarlos al paquete. Por ejemplo, convertir SASS / LESS a CSS normal o JavaScript moderno a ES5 para navegadores más antiguos.
Instalación de un paquete web
Después de inicializar el proyecto con npm, para que el paquete web funcione, debe instalar dos paquetes,
webpack
y webpack-cli
.
npm i webpack webpack-cli -D
webpack.config.js
Después de instalar estos paquetes, es necesario configurar el paquete web. Para ello, se crea un archivo
webpack.config.js
que exporta el objeto. Este objeto contiene la configuración del paquete web.
module.exports = {}
La tarea principal de un paquete web es analizar módulos, transformarlos opcionalmente y combinarlos de manera inteligente en uno o más paquetes, por lo que el paquete web necesita saber tres cosas:
- Punto de entrada de la aplicación
- Conversiones a realizar
- Dónde colocar el paquete generado
Punto de entrada
No importa cuántos módulos contenga una aplicación, siempre hay un único punto de entrada. Este módulo incluye el resto. Normalmente, este archivo es index.js. Podría verse así:
index.js
imports about.js
imports dashboard.js
imports graph.js
imports auth.js
imports api.js
Si le decimos al paquete web la ruta a este archivo, lo usa para crear el gráfico de dependencia de la aplicación. Para hacer esto, debe agregar una propiedad
entry
a la configuración del paquete web con el valor de la ruta al archivo principal:
module.exports = {
entry: './app/index.js'
}
Conversión con cargadores
Después de agregar el punto de entrada, debe informar al paquete web sobre las transformaciones que deben realizarse antes de generar el paquete. Para ello, se utilizan cargadores.
De forma predeterminada, al generar gráficos de dependencia basados en operadores, el
import / require()
paquete web solo puede procesar archivos JavaScript y JSON.
import auth from './api/auth' //
import config from './utils/config.json' //
import './styles.css' // ️
import logo from './assets/logo.svg' // ️
Es poco probable que te atrevas a limitarte a archivos JS y JSON en tu aplicación, lo más probable es que también necesites estilos, SVG, imágenes, etc. Ahí es donde entran los cargadores. La tarea principal de los cargadores, como su nombre lo indica, es permitir que el paquete web funcione con más que solo archivos JS y JSON.
El primer paso es instalar el cargador. Como queremos cargar SVG, use npm para instalar svg-loader.
npm i svg-inline-loader -D
A continuación, agréguelo a la configuración del paquete web. Todos los cargadores están incluidos en una serie de objetos
module.rules
:
module.exports = {
entry: './app/index.js',
module: {
rules: []
}
}
La información del cargador consta de dos partes. El primero es el tipo de archivos que se procesan (
.svg
en nuestro caso). El segundo es el cargador que se utiliza para procesar este tipo de archivo ( svg-inline-loader
en nuestro caso).
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' }
]
}
}
Ahora podemos importar archivos SVG. Pero, ¿qué pasa con nuestros archivos CSS? Para los estilos utilizados
css-loader
.
npm i css-loader -D
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: 'css-loader' }
]
}
}
Ahora podemos importar archivos SVG y CSS. Sin embargo, para que nuestros estilos funcionen correctamente, necesitamos agregar otro cargador. Gracias a
css-loader
nosotros, podemos importar archivos CSS. Pero eso no significa que se incluirán en el DOM. Queremos no solo importar dichos archivos, sino también colocarlos en una etiqueta <style>
para que se apliquen a los elementos DOM. Para esto necesitas style-loader
.
npm i style-loader -D
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }
]
}
}
Tenga en cuenta que, dado que se utilizan dos cargadores para procesar archivos CSS, el valor de la propiedad
use
es una matriz. También preste atención al orden de los cargadores, primero style-loader
, luego css-loader
. Es importante. El paquete web los aplicará en orden inverso. Se usa primero css-loader
para importaciones './styles.css'
, luego style-loader
para inyectar estilos en el DOM.
Los cargadores se pueden utilizar no solo para importar archivos, sino también para convertirlos. El más popular es convertir JavaScript de próxima generación a JavaScript moderno usando Babel. Se utiliza para esto
babel-loader
.
npm i babel-loader -D
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
}
}
Hay cargadores para casi cualquier tipo de archivo.
Punto de salida
Ahora el paquete web conoce el punto de entrada y los cargadores. El siguiente paso es especificar el directorio del paquete. Para hacer esto, agregue una propiedad
output
a la configuración del paquete web.
const path = require('path')
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
}
}
Todo el proceso se parece a esto:
- El paquete web recibe un punto de entrada ubicado en
./app/index.js
- Analiza declaraciones
import / require
y crea un gráfico de dependencia - El paquete web comienza a construir el paquete convirtiendo el código usando los cargadores apropiados
- Recoge un paquete y lo coloca en
dist/index_bundle.js
Complementos
Hemos visto cómo utilizar cargadores para procesar archivos individuales antes o durante la generación de un paquete. A diferencia de los cargadores, los complementos le permiten realizar tareas después de crear un paquete. Estas tareas pueden afectar tanto al paquete como a otro código. Puede pensar en los complementos como cargadores más potentes y menos limitados.
Pongamos un ejemplo.
HtmlWebpackPlugin
La tarea principal del paquete web es generar un paquete al que se puede hacer referencia en
index.html
.
HtmlWebpackPlugin
crea index.html
en el directorio con el paquete y agrega automáticamente un enlace al paquete que contiene.
Nombramos el paquete
index_bundle.js
y lo colocamos dist
. HtmlWebpackPlugin
creará un nuevo archivo index.html
en el directorio dist
y agregará un enlace al paquete en él - <script src='index_bundle.js'></script>
. Genial, ¿no? Desde que se index.html
genera HtmlWebpackPlugin
, aunque cambiemos el punto de salida o el nombre del paquete, HtmlWebpackPlugin
recibirá esta información y cambiará el contenido index.html
.
¿Cómo usamos este complemento? Como de costumbre, primero debe instalarlo.
npm i html-webpack-plugin -D
A continuación, agregue la propiedad a la configuración del paquete web
plugins
.
const path = require('path')
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
},
plugins: []
}
Creamos una instancia
HtmlWebpackPlugin
en una matriz plugins
.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin()
]
}
EnvironmentPlugin
Si está utilizando React, querrá establecer esto
process.env.NODE_ENV
en un valor production
antes de implementar la aplicación. Esto permitirá que React incorpore la producción al eliminar herramientas de desarrollo como las advertencias. El paquete web le permite hacer esto a través de un complemento EnvironmentPlugin
. Es parte del paquete web, por lo que no es necesario instalarlo.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
new webpack.EnvironmentPlugin({
'NODE_ENV': 'production'
})
]
}
Ahora, en cualquier lugar de nuestra aplicación, podemos configurar el modo de producción con
process.env.NODE_ENV
.
HtmlWebpackPlugin
y EnvironmentPlugin
es solo una pequeña parte del sistema de complementos del paquete web.
Modo (modo)
En el proceso de preparación de una solicitud para producción, hay varios pasos a seguir. Acabamos de cubrir uno de ellos: establecer el
process.env.NODE_ENV
valor production
. Otra acción es minimizar el código y eliminar comentarios para reducir el tamaño del paquete.
Hay complementos especiales para resolver estas tareas, pero hay una forma más sencilla. En la configuración de WebPack, se puede ajustar
mode
a development
o production
dependiendo del entorno de desarrollo.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './app/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin()
],
mode: 'production'
}
Tenga en cuenta que hemos eliminado
EnvironmentPlugin
. El hecho es que después de establecer mode
el valor, el production
paquete web asigna automáticamente el process.env.NODE_ENV
valor production
. Esto también minimiza el código y elimina las advertencias.
Lanzamiento de un paquete web
De momento sabemos cómo funciona el webpack y cómo configurarlo, queda ejecutarlo.
Tenemos un archivo
package.json
que podemos crear script
para ejecutar webpack
.
"scripts": {
"build": "webpack"
}
Ahora, cuando ejecute el comando
npm run build
en la terminal, se lanzará un paquete web, que creará un paquete optimizado index_bundle.js
y lo colocará dist
.
Modos de desarrollo y producción
Con todo, hemos terminado con el paquete web. Finalmente, echemos un vistazo a cómo cambiar entre modos.
Cuando construimos para producción, queremos optimizar todo lo más posible. En el caso del modo de desarrollo, ocurre lo contrario.
Para cambiar entre modos, necesita crear dos scripts en
package.json
.
npm run build
construirá el paquete de producción.
npm run start
iniciará el servidor de desarrollo y observará los cambios de archivo.
Si recuerda, lo configuramos
mode
en un valor production
en la configuración del paquete web. Sin embargo, no lo necesitamos ahora. Queremos que la variable de entorno tenga un valor apropiado dependiendo del comando que se esté ejecutando. Vamos a cambiar el guión build
en package.json
.
"scripts": {
"build": "NODE_ENV='production' webpack",
}
Si usted tiene Windows, el comando sería:
"SET NODE_ENV='production' && webpack"
.
Ahora en la configuración del paquete web podemos cambiar el valor
mode
dependiendo de process.env.NODE_ENV
.
...
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development'
}
Para crear un paquete listo para usar para nuestra aplicación, simplemente lo ejecutamos
npm run build
en la terminal. Los dist
archivos de directorio se crean index.html
y index_bunlde.js
.
Servidor de desarrollo
Cuando se trata de desarrollar una aplicación, la velocidad es fundamental. No queremos reiniciar el paquete web y esperar una nueva compilación con cada cambio. Aquí es donde el paquete resulta útil
webpack-dev-server
.
Como su nombre indica, este es un servidor webpack para desarrollo. En lugar de crear un directorio
dist
, almacena datos en la memoria y los procesa en un servidor local. Además, admite reinicio en vivo. Esto significa que cualquier cambio webpack-dev-server
reconstruirá los archivos y reiniciará el navegador.
Instale el paquete.
npm i webpack-dev-server -D
Todo lo que queda por hacer es agregar el script
start
a package.json
.
"scripts": {
"build": "NODE_ENV='production' webpack",
"start": "webpack-dev-server"
}
Ahora tenemos dos comandos: uno para iniciar el servidor de desarrollo y el otro para construir el paquete terminado.
Espero que el artículo te haya sido útil. Gracias por su atención.