Multiple Pages

RelativeCI - In-depth bundle stats analysis and monitoring - Interview with Viorel Cojocaru

Even though webpack is often used for bundling single-page applications, it's possible to use it with multiple separate pages as well. The idea is similar to the way you generated many output files in the Targets chapter. That's achievable through MiniHtmlWebpackPlugin and a bit of configuration.

If you want to map a directory tree as a website, see directory-tree-webpack-plugin.

Possible approaches#

When generating multiple pages with webpack, you have a couple of possibilities:

  • Go through the multi-compiler mode and return an array of configurations. The approach would work as long as the pages are separate, and there is a minimal need for sharing code across them.
  • Set up a single configuration and extract the commonalities. The way you do this can differ depending on how you chunk it up.
  • If you follow the idea of Progressive Web Applications (PWA), you can end up with either an app shell or a page shell and load portions of the application as it's used.

In practice, you have more dimensions. For example, you have to generate i18n variants for pages. These ideas grow on top of the basic approaches. Here we'll set up single configuration based on which to experiment further.

Generating multiple pages#

To generate multiple pages with webpack, we can leverage mini-html-webpack-plugin. html-webpack-plugin would work well for the purpose as well and using it would give you access to the plugins written for it. For the demonstration, using the former is enough.

A page should receive title, url, and chunks for deciding which scripts to include to the page. The idea can be modeled as a configuration part as below:

webpack.parts.js

const {
  MiniHtmlWebpackPlugin,
} = require("mini-html-webpack-plugin");

exports.page = ({ title, url = "", chunks } = {}) => ({
  plugins: [
    new MiniHtmlWebpackPlugin({
      publicPath: "/",
      chunks,
      filename: `${url && url + "/"}index.html`,
      context: { title },
    }),
  ],
});

To generate multiple pages using the new helper, set up a configuration file:

webpack.multi.js

const { merge } = require("webpack-merge");
const parts = require("./webpack.parts");

module.exports = merge(
  { mode: "production", entry: { app: "./src/multi.js" } },
  parts.page({ title: "Demo" }),
  parts.page({ title: "Another", url: "another" })
);

Implement a small module to render on the page:

src/multi.js

const element = document.createElement("div");
element.innerHTML = "hello multi";
document.body.appendChild(element);

And add a script to generate the pages:

package.json

{
  "scripts": {
"build:multi": "wp --config webpack.multi.js"
} }

Testing the build#

After these steps, you have a minimal build with two pages: / and /another. To see it in the browser, run npx serve dist to display the result. You should be able to navigate to both pages any other should not be available.

To control which entries are used on each page, use the chunks parameter of parts.page. If you set it to chunks: [] for one of the pages, you should see nothing on the page for example. While experimenting, match the name given at parts.entry. The parameter allows capturing chunks generated by Bundle Splitting and doing this would allow you to load a shared vendor bundle for all pages.

To support development mode, see the Composing Configuration chapter on how to set it up. The development target requires parts.devServer() helper and a more complex merge operation based on the target type.

Progressive web applications#

If you push the idea further by combining it with code splitting and smart routing, you'll end up with the idea of Progressive Web Applications (PWA). webpack-pwa example illustrates how to implement the approach using webpack either through an app shell or a page shell.

App shell is loaded initially, and it manages the whole application, including its routing. Page shells are more granular, and more are loaded as the application is used. The total size of the application is larger in this case. Conversely, you can load initial content faster.

Using Service Workers improves offline experience and especially Workbox and its associated workbox-webpack-plugin can be useful for setting up the approach with minimal effort.

Twitter and Tinder case studies illustrate how the PWA approach can improve platforms.

Conclusion#

Webpack allows you to manage multiple page setups. The PWA approach allows the application to be loaded as it's used and webpack allows implementing it.

To recap:

  • Webpack can be used to generate separate pages either through its multi-compiler mode or by including all the page configuration into one.
  • The multi-compiler configuration can run in parallel using external solutions, but it's harder to apply techniques such as bundle splitting against it.
  • A multi-page setup can lead to a Progressive Web Application. In this case, you use various webpack techniques to come up with an application that is fast to load and that fetches functionality as required. Both two flavors of this technique have their own merits.

You'll learn to implement Server-Side Rendering in the next chapter.

Previous chapter
Build Targets

This book is available through Leanpub (digital), Amazon (paperback), and Kindle (digital). By purchasing the book you support the development of further content. A part of profit (~30%) goes to Tobias Koppers, the author of webpack.

Need help?