Lesson Weekend

So far we've used webpack to bundle our JavaScript and CSS files. We can also use webpack to generate HTML files for us.

Why would we do this? Well, a larger application might have many entry points. What if someone adds an entry point or changes the output configuration in webpack.config.js? Our HTML file's script tags would need to be updated, too. That might lead to errors and it's not very DRY. A bigger application could have many HTML files, all with multiple different entry points. Ideally, we should only have to update our configuration file and then webpack will handle the rest for us.

webpack Plugins

To add this functionality to webpack, we'll use our first plugin: HtmlWebpackPlugin.

What's the difference between a webpack loader and a webpack plugin?

  • Loaders preprocess code, generally before or during the process of creating our bundle. They work with single files.

  • Plugins are more powerful. They can modify and work with the entire bundle, so they generally run after the bundle has been created.

Note: You can continue using webpack without knowing the difference between loaders and plugins. If this is still confusing, feel free to keep on moving. For the most part, once we have an environment set up, we can forget about it - at least until we need to add or update new packages.

Before we install the plugin, let's move our index.html file from the dist folder to the src folder. From now on, we'll let webpack handle bundling our HTML and outputting it to dist. This is why dist/ is in our .gitignore file - webpack will automatically generate everything inside this directory for us. Any developer can clone our project and then build it from our source code - so it would be redundant to push that code to GitHub.

Now let's add another dev dependency with npm:

$ npm install [email protected] --save-dev

Let's also update webpack.config.js:

webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Shape Tracker',
      template: './src/index.html',
      inject: 'body'
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      }
    ]
  }
};
  • First we require html-webpack-plugin and make it available to our application.

  • Next we add a section to our configuration file for plugins.

  • Finally, we instantiate a new HtmlWebpackPlugin. Our instantiated plugin is taking three arguments:

    • title: This will be the title of our bundled HTML file.
    • template: This is the HTML file we'll bundle. Here we specify that it should be the index.html file we just moved to the src folder. If we didn't specify a template file, then webpack would just generate a file with a <head> and <title> and <script> tags.
    • inject: This is a nice little option. webpack will inject our script at the bottom of our HTML for us. It's yucky to put script tags in the body when we're writing code because it's hard to read and mixes HTML and JS, which are separate concerns. However, our code will be more performant in production if we put our script tags there. webpack gives us the best of both worlds. We can write clean code when we're developing and then let webpack make it more performant for us by moving the script tags to the bottom of the HTML.

Also, because all the code in our HTML file will load synchronously, line by line, putting our script tags at the end of our HTML file means that we no longer need to use $(document).ready() in our code - because it does the exact same thing - wait until the rest of the document is loaded before loading our scripts.

Note: Many students have found that their projects load faster in development when they use inject: 'head' instead of inject: 'body'. Ultimately, you may use either option based on your preferences. As always, keep in mind that having the script at the end of the body is preferable for production sites.

Before we $ npm run build our application again, let's remove the <script> tag currently linking our bundled JavaScript from index.html. Here's the updated <head>:

src/index.html
...
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <title>Shape Tracker</title>
</head>
...

Now run $ npm run build. webpack will add index.html to our dist folder for us. If you take a look, you'll see that webpack has added a script tag for our bundled JavaScript to the bottom of our HTML file.

At this point, we can open dist/index.html (either by opening it in the browser or with Live Server), and our site will be there. Everything appears exactly the same - but our code is now bundled.

Lesson 14 of 48
Last updated more than 3 months ago.