DEV Community

Marcin Wosinek
Marcin Wosinek

Posted on • Updated on

webpack 5 - tutorial for building multipage website

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;
  }, {}),
Enter fullscreen mode Exit fullscreen mode

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

{
  a: '.src/a.js',
  b: '.src/b.js'
}
Enter fullscreen mode Exit fullscreen mode

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
  ),
Enter fullscreen mode Exit fullscreen mode

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",
    },
  },
Enter fullscreen mode Exit fullscreen mode

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],
        })
    )
  ),
};
Enter fullscreen mode Exit fullscreen mode

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

Links

Want's more?

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

Discussion (6)

Collapse
ourmaninindia profile image
Alfred Tuinman

So far so good but I am stuck as to how I can add database content at a pre-render stage so that ejs templating can be used? I don't want to do DOM manipulation.

Collapse
marcinwosinek profile image
Marcin Wosinek Author

sounds more like a job for a tool like NextJs. Doing it with webpack will be probably doable - the is plenty of loaders etc. but I'm afraid you will get to uncharted territory pretty fast.

Collapse
ourmaninindia profile image
Alfred Tuinman

I am a plain vanilla user so I don't think NextJs is my cup of tea.

Thread Thread
marcinwosinek profile image
Marcin Wosinek Author

What DB you want to connect to? Is it something that could be replaced with flat MD or text files in the repo?

Thread Thread
ourmaninindia profile image
Alfred Tuinman

actually I am using fetch to connect to the url which links to a MS-SQL database. It's a large db and the site I am converting from a Delphi based program to a microservice.

Thread Thread
marcinwosinek profile image
Marcin Wosinek Author

For me it sounds you are more in static page generation area, and less in the JS applications where webpack thrives.

You can consider:

  • writing a script to load the existing content, to include it in the new repository. Downside - you will replace DB with static files in the repo. This will change the workflow with content authoring. Once you have content locally, you will need to figure out importing it with wepback
  • use similar script, but on the build time. So data will live where you have it now, and each build will reload it's current state
  • write an application that loads data dynamically, from the browser