> Manuales > Manual de Webpack

Cómo usar HTML Webpack Plugin para que Webpack procese los archivos HTML y les pueda inyectar el código de Javascript generado al producir el bundle, de modo que puedas producir también el HTML en el momento del build del proyecto.

HTML Webpack Plugin: Inyectar bundles en el HTML

En este artículo vamos a continuar ofreciendo las guías esenciales para aprender a usar Webpack. Es un artículo que ofrece un paso más en la configuración de un entorno de trabajo para un proyecto frontend. Recuerda que en el punto anterior del Manual de Webpack pudimos aprender a transpilar código a ES5 y hemos generado nuestro primer bundle a partir de varios módulos Javascript.

Lo que nos proponemos ahora es colocar el archivo del bundle en el código HTML. Alguien podría pensar que ésta sería una tarea completamente trivial, pues realmente se trata de colocar una etiqueta SCRIPT en un archivo HTML. Lo podríamos hacer de manera manual una vez y listo! Pero no siempre será así. El plugin que estamos aprendiendo puede servirnos para inyectar Javascript, CSS, el manifest o archivos favicon. Incluso facilitarnos la tarea de enlazar con un archivo Javascript que tenga un hash al final, de modo que en cada actualización cambie su nombre y se eviten efectos poco deseables en la etapa de desarrollo, como que se cacheen por el navegador en las actualizaciones de página.

Todo lo que vamos a necesitar es un plugin de Webpack llamado HTML Webpack Plugin.

Instalación de HTML Webpack Plugin

Instalamos el plugin de webpack para inyectar el script generado en el HTML.

npm i -D html-webpack-plugin

Ahora podemos usar ese plugin desde la configuración de Webpack. Se trataría de hacerlo en dos pasos, pero vamos a ver el código completo de nuestro webpack.config.js.

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin()
  ]
}

Ahora podemos ejecutar webpack para comprobar esta configuración, con el comando "webpack --mode production" o algo como "npm run build" si es que has creado el correspondiente script en package.json.

Obviamente, solamente con esta configuración seguramente no se adapte a nuestras necesidades, pero el plugin ya realizará un comportamiento. Simplemente generará un archivo llamado index.html en la carpeta "dist".

Además, en el código del archivo HTML generado observarás que, sin necesidad de pedirle nada, ya coloca una etiqueta SCRIPT que cargará el código de main.js, el bundle principal.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
  <script type="text/javascript" src="main.js"></script></body>
</html>

Opciones de HTML Webpack Plugin

Este plugin tiene la posibilidad de usar una serie de opciones de diverso interés. Para cargarlas usamos un objeto que tenemos que enviar como parámetro en la instanciación del plugin. Algunas de las más destacadas son.

Nota: Si usamos la configuración "template" no se cargará automáticamente el título que definas en la opción "title". Puedes enviar el título y cualquier otro dato, del template al HTML generado, por medio de los templateParameters.

Existen muchas otras configuraciones, que puedes ver en la documentación de HTML Webpack Plugin. Ahora puedes ver un ejemplo sencillo de uso.

plugins: [
    new HtmlWebpackPlugin({  
      filename: 'index.html',
      template: 'src/index.html',
      templateParameters: {
        titulo: 'Manual de Webpack en Desarrolloweb',
        encabezamiento: 'Aprendo Webpack en DesarrolloWeb.com',
      }
    })
  ]

Ahora veamos el código de nuestro template, donde veremos cómo se insertan los parámetros.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title><%= titulo %></title>
</head>
<body>
  <h1><%= encabezamiento%></h1>
</body>
</html>

Al ejecutarse ahora Webpack obtendremos este código HTML generado.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Manual de Webpack en Desarrolloweb</title>
</head>
<body>
  <h1>Aprendo Webpack en DesarrolloWeb.com</h1>
<script type="text/javascript" src="main.js"></script></body>
</html>

Como resultado de esta acción tendríamos en la carpeta "dist", o cualquier otra que tengas configurada como output en webpack.config.js, los archivos de:

Localizando ese index.html con el explorador de archivos o finder, podríamos hacer doble clic sobre él para abrirlo y comprobar que el código transpilado, e inyectado como script en el HTML, se está ejecutando correctamente.

Cambiando las rutas del archivo .html generado

Ten en cuenta que las rutas del archivo HTML de destino y el template de origen pueden cambiar, depende de cómo tengas organizado el input y output del sistema de build de Webpack.

new HtmlWebpackPlugin({
      filename: '../index.html',
      template: 'src/index.html',
}),

Ese código permitiría que el archivo .html generado se coloque en la carpeta padre de donde vayas a colocar el Javascript. Por ejemplo, imagina que el output lo tienes en "dist/js", entonces el archivo .html generado se quedará en la carpeta "dist", que seguramente es lo que quieras. Sin embargo, esta configuración nos daría problemas cuando queramos usar WebpackDevServer, por lo que la solución que nosotros recomendaríamos sería:

Definir el output de esta manera en el archivo webpack.config.js:

output: {
    path: path.resolve(__dirname, 'www'),
    filename: 'js/game.js',
},

Luego definir el plugin de HTMLWebpackPlugin como habíamos mencionado al principio:

new HtmlWebpackPlugin({
  filename: 'index.html',
  template: 'src/index.html',
}),

De todos modos, esto realmente lo tendrás que ajustar en tu proyecto para que vaya todo como tú necesites. Quizás a la primera no te funcione todo, pero con alguna prueba extra lo dejarás bien fino.

Hash en el nombre de archivo del bundle

Ya que lo mencionábamos al principio del artículo, acabamos explicando cómo hacer uso de un hash para el nombre del archivo del bundle. Es tan sencillo como activar una de las configuraciones de instanciación del plugin.

plugins: [
  new HtmlWebpackPlugin({  
    hash: true
  })
]

Una vez ejecutado el proceso de build con Webpack, podrás apreciar que en el HTML generado ahora aparece el hash en la ruta del script del bundle. Verás algo como esto:

<script type="text/javascript" src="main.js?9992c496ace80a68b76e"></script>

Producir varios archivos HTML

Si tenemos la necesidad de producir varios archivos de HTML como salida, en output, podemos hacerlo fácilmente con la instanciación de varios objetos del plugin HTML Webpack Plugin, colocados en el array "plugins" del webpack.config.js. Cada una de las instanciaciones generará un archivo. La única cosa es que tendremos que pasarle a cada instanciación un nombre de archivo distinto en la opción "filename", puesto que si no se hace así, se sobreescribirán las distintas salidas en el mismo "index.html".

El código nos podría quedar más o menos como este:

plugins: [
  new HtmlWebpackPlugin({  
    filename: 'index.html',
    template: 'src/index.html',
    hash: true,
    templateParameters: {
      titulo: 'Manual de Webpack en Desarrolloweb',
      encabezamiento: 'Aprendo Webpack en DesarrolloWeb.com',
    }
  }),
  new HtmlWebpackPlugin({
    filename: 'standar.html'
  }),
  new HtmlWebpackPlugin({
    filename: 'index2.html',
    template: 'src/index.html',
    templateParameters: {
      titulo: 'Curso de Webpack de EscuelaIT',
      encabezamiento: 'Aprendo mucho más Webpack en Escuela.it',
    }
  }),
  new ScriptExtHtmlWebpackPlugin({
    custom: [
      {
        test: /\.js$/,
        attribute: 'nomodule',
        value: 'nomodule'
      },
    ]
  })
]

Fíjate que los filemane cambian para cada instanciación. Además, si estamos enviando parámetros al template, podremos generar código HTML con distinto contenido, lo que nos da una idea de cómo generar código estático a través de Webpack. No obstante, existen diversos sistemas de templates que nos pueden ayudar mejor en esta tarea, así como librerías más complejas para conseguir generar esos archivos estáticos a partir de datos que tengamos en algún depósito de almacenamiento.

Colocar otros scripts

Hay veces que usas dependencias de librerías Javascript que quieres colocar tal cual en el HTML, sin incluirlas con los correspondientes requires o imports, de modo que Webpack no las tenga que procesar cuando estás compilando el proyecto.

Ponte el caso que estás usando jQuery y que simplemente quieres poner el código a disposición, con una etiqueta SCRIPT, para que esté disponible. O que estés realizando un juego con Phaser y solamente quieras disponer del script de Phaser en la página. En estos casos puedes, por qué no, colocarlo como un script en el HTML. HTML-Webpack-plugin no lo tocará y tendrás disponible ese código, sin necesidad que Webpack lo procese en cada build.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Juego con Phaser</title>
  <style>
    body {
      background-color: #243A3E;
    }
  </style>
</head>
<body>
  
  <script src="phaser.min.js"></script>
  
</body>
</html>

En un caso como este, HTML Webpack Plugin hará lo que se supone que debe hacer, que es inyectar el código del bundle generado con Webpack justo antes del cierre de la etiqueta BODY.

Conclusión

HTML Webpack Plugin es uno de los plugins indispensables para Webpack. Esperamos que te hayamos aclarado algunas de sus utilidades principales. Nos hemos centrado en la inyección de los scripts Javascript del bundle, pero lo cierto es que hace muchas otras cosas.

Ahora que ya tienes claro cómo crear tu archivo HTML e inyectarle el script de Javascript compilado por Webpack, estás en condiciones de aprender otra de las grandes utilidades de Webpack, como es el uso de un servidor de desarrollo que permita ejecutar el proyecto frontend.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual