1. 1. Why bother
  2. 2. Node modules setup
  3. 3. Project setup
    1. 3.1. File contents
  4. 4. Basic configuration
  5. 5. Advanced configuration
    1. 5.1. Manually include CSS and JS
      1. 5.1.1. More control
      2. 5.1.2. Async CSS
      3. 5.1.3. That’s it!

Using HTMLWebpackPlugin and Pug

HTMLWebpackPlugin is a simple way to generate the html files for your web app. By default it will create an HTML5 file that includes all your bundled code (script and style tags etc).

Using it can be as simple as the following:

1
2
3
4
5
6
7
8
9
10
/* webpack.config.js */
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: 'main.js',
output: {
path: path.resolve(__dirname, 'dist'), // Output folder
filename: 'js/app.js' // JS output path
},
plugins: [new HtmlWebpackPlugin()]
}

This would generate a generic index.html that includes your javascript bundle.

If you don’t know what Pug is, it’s a whitespace based template engine, implemented in JS for Node.js / Browsers. Pug.js website

Why bother

The default HTML file generated by the plugin is suitable for many projects. If you only need an index.html to deliver your JS then you won’t need to move away from the default / simplest settings.

If you need a more customised HTML file though, you have a couple of options. You can pass an HTML file and the plugin will inject your files, you can use Lodash templates or you can use a templating engine with its corresponding loader. We are going to look at using Pug.

Node modules setup

The minimum setup for this is pretty simple. The modules we need to npm install are:

  • webpack
  • html-webpack-plugin
  • pug
  • pug-loader
  • css-loader
  • style-loader
  • extract-text-webpack-plugin

Project setup

We will structure our project like this (note: we are not going to put much in the css or js file - just enough to confirm they are being included):

| Source files

1
2
3
4
5
6
7
8
9
10
webpack.config.js
src/
├── main.js
├── styles.css
└── templates/
├── includes/
│ ├── head.pug
│ └── foot.pug
├── layout.pug
└── index.pug

File contents

Our files are going to be kept as simple as possible, as the contents are fairly irrelevant to the implementation. Our pug file is going to broken up a bit just as a demonstration. (Using github gist as highlight.js doesn’t currently support pug syntax)

| Pug templates

| CSS

1
2
3
4
/* styles.css */
* {
color: red;
}

| JS

1
2
3
/* main.js */
import './styles.css'
alert('Success!')

Basic configuration

The basic configuration to start generating your HTML files from pug templates is really simple.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* webpack.config.js */
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'), // Output folder
filename: 'js/app.js' // JS output path
},
module: {
rules: [
// Include pug-loader to process the pug files
{
test: /\.pug$/,
use: 'pug-loader'
},
// Include css/style loaders to process our css files
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
]
},
plugins: [
// Extract our css to a seperate css file
new ExtractTextPlugin('css/styles.css'),
// Use HTMLWebpackPLugin with template set to our pug template.
new HTMLWebpackPLugin({
template: './src/template/index.pug'
})
]
}

After running webpack we will have an index.html file in our dist/ folder. We can see that our pug content has been used and we can see that our CSS and JS are included and working as the text is red and we get a ‘Success’ alert on load.

Something like:

Select S3 bucket properties panel

Advanced configuration

We can customise our HTML generation further. Currently HTMLWebpackPlugin is automatically injecting our JS and CSS files into our template, but perhaps we want to manually control where in the document these occur.

We can achieve this by setting inject to false.

1
2
3
4
5
6
7
8
9
/* webpack.config.js */
...
// Use HTMLWebpackPLugin with template set to our pug template.
new HTMLWebpackPLugin({
template: './src/template/index.pug',
inject: false
})
...

If we reload our HTML file now, we can see that the CSS and JS are no longer being loaded. We just have boring black text with no exciting alerts 😞 .

Manually include CSS and JS

To include our bundles in the correct location in our HTML, we can use pug variables. HTMLWebpackPlugin makes our bundled files available as local variables in our pug template.

If we reload our page after this change, we can see it is back to red text with our exciting ‘Success’ alert.

More control

This means we can have more control over how our bundles are included in the HTML, for instance we can ensure our JS is loaded async or deferred.

Async CSS

We could also load our CSS asynchronously, using this loadCSS function from filament group:

This would be useful in a situation where we are inlining our critical CSS into our HTML and we want to load the rest of the styles after the initial render. You can find out a bit more about critical css and why you may want it in this Google Pagespeed article.

That’s it!

That’s pretty much all there is to generating your HTML from pug templates with the HTMLWebpackPlugin. Other templating engines should behave roughly the same as the behaviour is provided by HTMLWebpackPlugin itself, I can’t confirm this though as I don’t really use other engines.