How to building multipage website with webpack 5

Have you ever wondered how to build multiple-page website with webpack? If that's your case - either due to maintaining a legacy page, or some current architectural decisions - the materials focused on single-page-app (SPA) can leave you with some doubts.

Define dynamically an entry for each page

In our case, we need to define one entry for each page. Assuming we have a list of pages in an array pages = ['a', 'b'], the entry: section of webpack config can look like:

  entry: pages.reduce((config, page) => {
    config[page] = `./src/${page}.js`;
    return config;
  }, {}),

with just a bit of functional programming, we turned the pages list into:

{
  a: '.src/a.js',
  b: '.src/b.js'
}

that we can set to entry. Because of doing it this way, the next time when we add a new page, it will be just adding one element to the list, without copy&pasting code.

Inject all the necessary code to html

Same as with SPAs, we want to inject the imports dynamically into your html. For that we useHtmlWebpackPlugin. Again, we want to use our pages array, so we avoid repeating code when we add new pages. So we will build our plugins: dynamically & we will leave a place to add some other, unrelated plugins there too.

  plugins: [].concat(
    pages.map(
      (page) =>
        new HtmlWebpackPlugin({
          inject: true,
          template: `./${page}.html`,
          filename: `${page}.html`,
          chunks: [page],
        })
    ),
    // <- here goes array(s) of other plugins
  ),

Optimization

To get the most out of our architecture, we need to split built code into chunks. That will allow us to reuse portions of code if they are big enough and used across multiple pages. Luckily, we can achieve that by just adding:

  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },

Complete configuration & example app

The complete, working configuration:

const path = require("path"),
  HtmlWebpackPlugin = require("html-webpack-plugin");

const pages = ["a", "b"];

module.exports = {
  entry: pages.reduce((config, page) => {
    config[page] = `./src/${page}.js`;
    return config;
  }, {}),
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "dist"),
  },
  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },
  plugins: [].concat(
    pages.map(
      (page) =>
        new HtmlWebpackPlugin({
          inject: true,
          template: `./${page}.html`,
          filename: `${page}.html`,
          chunks: [page],
        })
    )
  ),
};

To play with it, the easiest way is to check out the repo of an example app: github.com/marcin-wosinek/webpack-multipage..

Want's more?

I published a video course about webpack.

Here you can find me going through the example with details: