In large-scale projects, Multi-Page Application (MPA) architectures are often used to manage the independent state and lifecycle of different pages. Webpack provides flexible configuration options, enabling developers to efficiently build and optimize multi-page applications.
Multi-Page Application Overview
A multi-page application typically consists of multiple independent HTML pages, each with its own entry point and associated resources. In Webpack, you can define an entry point for each page and specify its output path and filename.
Entry Configuration
The entry property in Webpack’s configuration defines the application’s entry points. For a multi-page application, entry can be an object where keys represent page names and values point to the corresponding entry files.
// webpack.config.js
module.exports = {
entry: {
page1: './src/page1/index.js',
page2: './src/page2/index.js',
},
// ...
};Output Configuration
The output configuration determines the location and naming convention of output files. In a multi-page application, you typically specify different output directories for each page.
// webpack.config.js
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
// ...
};Here, [name] is replaced with the entry point name, resulting in files like page1.bundle.js and page2.bundle.js.
HTMLWebpackPlugin
The HTMLWebpackPlugin is a commonly used Webpack plugin that automatically generates HTML files and injects the generated JavaScript and CSS files. For a multi-page application, you can configure an instance for each page.
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/page1/index.html',
filename: 'page1.html',
chunks: ['page1'],
}),
new HtmlWebpackPlugin({
template: './src/page2/index.html',
filename: 'page2.html',
chunks: ['page2'],
}),
],
// ...
};Shared Code and Resources
In a multi-page application, some code and resources, such as common stylesheets or script libraries, may be needed by all pages. The SplitChunksPlugin can extract this shared code into separate chunks.
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
// ...
};Dynamic Imports and Lazy Loading
Dynamic imports (import()) and lazy loading can further optimize multi-page application performance by loading page-specific code only when needed.
// src/page1/index.js
import(/* webpackChunkName: "page1" */ './page1-component').then((Component) => {
// Use the component
});Code Example Analysis
Let’s analyze a Webpack configuration for a multi-page application with a concrete example.
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
page1: './src/page1/index.js',
page2: './src/page2/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/page1/index.html',
filename: 'page1.html',
chunks: ['page1', 'vendors'],
}),
new HtmlWebpackPlugin({
template: './src/page2/index.html',
filename: 'page2.html',
chunks: ['page2', 'vendors'],
}),
],
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
};src/page1/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));src/page1/index.html
<!DOCTYPE html>
<html>
<head>
<title>Page 1</title>
</head>
<body>
<div id="root"></div>
</body>
</html>Custom Templates and Dynamic Data Injection
HTMLWebpackPlugin allows the use of custom HTML templates and supports injecting dynamic data into generated HTML files. This is particularly useful for dynamically generating titles, meta tags, or page content.
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: './src/page1/index.html',
filename: 'page1.html',
chunks: ['page1', 'vendors'],
inject: 'body', // Inject scripts into the body
minify: { // HTML minification options
collapseWhitespace: true,
},
// Dynamic data
title: 'My Page 1',
meta: '<meta name="description" content="Description of page 1">',
}),
// ...
],
};Server-Side Rendering (SSR)
In multi-page applications, server-side rendering can improve first-page load times and SEO friendliness. Webpack can integrate with frameworks like Next.js or Nuxt.js to implement SSR.
On-Demand Loading and Code Splitting
On-demand loading and code splitting are particularly important in multi-page applications to reduce initial load times. Using dynamic imports (import()) and Webpack’s SplitChunksPlugin, you can achieve finer-grained code splitting.
// webpack.config.js
module.exports = {
optimization: {
runtimeChunk: 'single', // Extract runtime code into a single chunk
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
common: {
name: 'common',
minChunks: 2, // Referenced by at least two chunks
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};Static Asset Handling
For static assets like images and fonts in a multi-page application, loaders such as file-loader or url-loader can ensure proper bundling and referencing.
// webpack.config.js
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, // Inline images smaller than 8KB as base64 data URLs
name: '[name].[hash:8].[ext]',
outputPath: 'images/', // Output directory
},
},
],
},
// ...
],
},Build Process Optimization
For large multi-page applications, build times can become a bottleneck. Tools like thread-loader can leverage multi-core CPUs, and cache-loader can cache intermediate results to speed up the build process.



