Webpack: una guía para principiantes





¡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:



  1. ¿Por qué se necesita esta herramienta?
  2. ¿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, webpacky 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.jsque 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:



  1. Punto de entrada de la aplicación
  2. Conversiones a realizar
  3. 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 entrya 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 ( .svgen nuestro caso). El segundo es el cargador que se utiliza para procesar este tipo de archivo ( svg-inline-loaderen 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-loadernosotros, 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 usees 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-loaderpara importaciones './styles.css', luego style-loaderpara 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 outputa 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:



  1. El paquete web recibe un punto de entrada ubicado en ./app/index.js
  2. Analiza declaraciones import / requirey crea un gráfico de dependencia
  3. El paquete web comienza a construir el paquete convirtiendo el código usando los cargadores apropiados
  4. 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.



HtmlWebpackPlugincrea index.htmlen el directorio con el paquete y agrega automáticamente un enlace al paquete que contiene.



Nombramos el paquete index_bundle.jsy lo colocamos dist. HtmlWebpackPlugincreará un nuevo archivo index.htmlen el directorio disty agregará un enlace al paquete en él - <script src='index_bundle.js'></script>. Genial, ¿no? Desde que se index.htmlgenera HtmlWebpackPlugin, aunque cambiemos el punto de salida o el nombre del paquete, HtmlWebpackPluginrecibirá 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 HtmlWebpackPluginen 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_ENVen un valor productionantes 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.



HtmlWebpackPluginy EnvironmentPlugines 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_ENVvalor 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 modea developmento productiondependiendo 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 modeel valor, el productionpaquete web asigna automáticamente el process.env.NODE_ENVvalor 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.jsonque podemos crear scriptpara ejecutar webpack.



"scripts": {
  "build": "webpack"
}


Ahora, cuando ejecute el comando npm run builden la terminal, se lanzará un paquete web, que creará un paquete optimizado index_bundle.jsy 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 buildconstruirá el paquete de producción.



npm run startiniciará el servidor de desarrollo y observará los cambios de archivo.



Si recuerda, lo configuramos modeen un valor productionen 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 builden 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 modedependiendo 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 builden la terminal. Los distarchivos de directorio se crean index.htmly 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-serverreconstruirá 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 starta 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.



All Articles