How does html-webpack-plugin work with html-loader?

Shawn Chen picture Shawn Chen · Dec 27, 2017 · Viewed 8.8k times · Source

I thought a loader is invoked only when some resource is imported or required somewhere and the resources match with such a loader.

But in the following codes, no html file is imported anywhere but the html-loader is still necessary to make the compilation pass because of the underscore template stuff in the html.

So I have the following questions:

  1. When does the html-loader come to play? After or before the bundle is generated?
  2. Why does webpack invoke the html-loader? Because of the template setting in the plugin?
  3. Does the plugin use the output of the loader? But the output is just a string and how could it make a difference?

    //webpack.config.js
    const webpack = require('webpack');
    const path = require('path');
    const htmlPlugin = require('html-webpack-plugin');
    module.exports = {
        entry: {
            a: './a.js'
        },
        output: {
        filename: '[name].[chunkhash].js',
        chunkFilename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
        {
          test: /\.html$/,
          loader: "html-loader"
        }
        ]
    },
    plugins: [
            new htmlPlugin({
            template:path.resolve(__dirname,'index.html')
    
        })
    ]
    };  
    
    //index.html
        <!DOCTYPE html>
        <html>
        <head>
            <title></title>
        </head>
        <body>
            <script id="item-template" type="text/template">    
            <label><%= title %></label>
          </script>
    
        </body>
        </html>
    

Answer

user1275105 picture user1275105 · Jul 7, 2019

As you said, Webpack only knows about files when you are 'importing' them, otherwise it doesn't know.

However, Webpack first comes into contact with your html file via html-webpack-plugin. You are probably using html-webpack-plugin for templating reasons. I am using it purely to allow webpack to insert the generated JS and CSS bundle into the html automatically. My bundle file names contain "hashes" (e.g. bundle.b88ef660a5aa8442f616.js). I don't want to be doing this by hand.

At this point, html-loader has nothing to do with html-webpack-plugin. The reason why you might additionally use html-loaderis explained below.

What if your template contains images? What some people do (and it's the wrong thing to do) is use copy-webpack-pluginto copy the images folder into the output/dist folder and reference any images in the html relative to that folder. This is wrong because you images are bypassing webpack and losing on webpack benefits like adding hashing to image names, optimising images, tree shaking, etc. If you do this, webpack has no idea about your images and you have to manually look after your images folder.

The 'proper' way is to let webpack know about your image dependancies by 'requiring' the images. So instead of <img src="./img/my-image.jpg"> in the html, you should write <img src="${require(./img/my-image.jpg)}" />. BUT changing all your images references to the require version is cumbersome, so that's when you use the html-loader, it will do that automatically for you.

This may cause an error immediately. The error will be something along the lines of Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this file type.

All that error means is that webpack doesn't know how to handle images. And to tell webpack how to handle something it doesn't know about, you need to use the appropriate loader. In this case, file-loader.

Above is the most common use that I have come across of using webpack-html-plugin and html-loader.