jantimon/html-webpack-plugin

Use with Multi-Page Applications

christianitis opened this issue · 3 comments

Is your feature request related to a problem? Please describe.
I have a few folders, each containing an HTML file and its respective script file. In addition to that, I also have a library folder with a few script files that are reused by some of the individual scripts.

When I use the plugin, every single one of my entry points are included in each HTML file's <script> tags, regardless of if the page's related script file uses them or not.

Describe the solution you'd like
I'm not sure if this is an issue with my webpack.config.js file, or if I'm just not using the plugin correctly, or if this is even the intended purpose of this plugin. Any and all help is appreciated.

Describe alternatives you've considered
I suppose I could instead use the CopyWebpackPlugin?

Additional context
My config file looks like this:

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

module.exports = {
entry: {
example: "./src/example/example.ts", //
},
target: ["web"],
mode: "production",
devtool: 'inline-source-map',
module: {
rules: [
{
test: /.tsx?$/,
use: ['ts-loader'],
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: '[name]/[name].js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new HtmlWebpackPlugin({ template: './src/example/example.html', filename: 'example/example.html'}),
],
};

Any help would be greatly appreciated. Thanks.

Your HtmlWebpackPlugin or each of them (if you have multiple page) should have chunks property so you can List all entries which should be injected. The default value for chunks is "all", that's why all script files are getting included on your HTML file.

So, you should have this config.

plugins: [
new HtmlWebpackPlugin({ 
    template: './src/example/example.html', 
    filename: 'example/example.html',
    chunks: ['example'] // from your entry
  }),
],

@christianitis

The simplest and right way is to specify all script and style source files directly in the each HTML template.
The html-bundler-webpack-plugin allows you to do this.

Using this plugin, an entry point is an HTML template. A source file can be a relative path or Webpack alias.

For example, there is ./src/views/pages/home/index.html

<html>
<head>
  <!-- load source styles here -->
  <link href="./home.scss" rel="stylesheet">
  <!-- load source scripts here -->
  <script src="@scripts/common.js" defer="defer"></script>
  <script src="./home.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

and there is ./src/views/pages/about/index.html

<html>
<head>
  <!-- load source styles here -->
  <link href="./about.scss" rel="stylesheet">
  <!-- load source scripts here -->
  <script src="@scripts/common.js" defer="defer"></script>
  <script src="./about.js" defer="defer"></script>
</head>
<body>
  <h1>About</h1>
</body>
</html>

Very simple Webpack config for multiple pages using the html-bundler-webpack-plugin:

const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = {
 resolve: {
    alias: {
      '@scripts': path.join(__dirname, 'src/scripts'),
    },
  },
  plugins: [
    new HtmlBundlerPlugin({
      entry: {
        // define templates here, syntax is the same as Webpack entry
        index: 'src/views/home/index.html', // output dist/index.html
        'pages/about': 'src/views/about/index.html', // output dist/pages/about.html
      },
      js: {
        // output filename of extracted JS from source script loaded in HTML via `<script>` tag
        filename: 'js/[name].[contenthash:8].js',
      },
      css: {
        // output filename of extracted CSS from source style loaded in HTML via `<link>` tag
        filename: 'css/[name].[contenthash:8].css',
      },
    }),
  ],
  // ... loaders for styles, images, etc.
};

The generated dist/index.html:

<html>
<head>
  <link href="css/home.05e4dd86.css" rel="stylesheet">
  <script src="js/common.f4b855d8.js" defer="defer"></script>
  <script src="js/home.55d8f4b8.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

The generated dist/pages/about.html:

<html>
<head>
  <link href="css/about.05e4dd86.css" rel="stylesheet">
  <script src="js/common.f4b855d8.js" defer="defer"></script>
  <script src="js/about.55d8f4b8.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

@christianitis

The simplest and right way is to specify all script and style source files directly in the each HTML template. The html-bundler-webpack-plugin allows you to do this.

Using this plugin, an entry point is an HTML template. A source file can be a relative path or Webpack alias.

For example, there is ./src/views/pages/home/index.html

<html>
<head>
  <!-- load source styles here -->
  <link href="./home.scss" rel="stylesheet">
  <!-- load source scripts here -->
  <script src="@scripts/common.js" defer="defer"></script>
  <script src="./home.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

and there is ./src/views/pages/about/index.html

<html>
<head>
  <!-- load source styles here -->
  <link href="./about.scss" rel="stylesheet">
  <!-- load source scripts here -->
  <script src="@scripts/common.js" defer="defer"></script>
  <script src="./about.js" defer="defer"></script>
</head>
<body>
  <h1>About</h1>
</body>
</html>

Very simple Webpack config for multiple pages using the html-bundler-webpack-plugin:

const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = {
 resolve: {
    alias: {
      '@scripts': path.join(__dirname, 'src/scripts'),
    },
  },
  plugins: [
    new HtmlBundlerPlugin({
      entry: {
        // define templates here, syntax is the same as Webpack entry
        index: 'src/views/home/index.html', // output dist/index.html
        'pages/about': 'src/views/about/index.html', // output dist/pages/about.html
      },
      js: {
        // output filename of extracted JS from source script loaded in HTML via `<script>` tag
        filename: 'js/[name].[contenthash:8].js',
      },
      css: {
        // output filename of extracted CSS from source style loaded in HTML via `<link>` tag
        filename: 'css/[name].[contenthash:8].css',
      },
    }),
  ],
  // ... loaders for styles, images, etc.
};

The generated dist/index.html:

<html>
<head>
  <link href="css/home.05e4dd86.css" rel="stylesheet">
  <script src="js/common.f4b855d8.js" defer="defer"></script>
  <script src="js/home.55d8f4b8.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

The generated dist/pages/about.html:

<html>
<head>
  <link href="css/about.05e4dd86.css" rel="stylesheet">
  <script src="js/common.f4b855d8.js" defer="defer"></script>
  <script src="js/about.55d8f4b8.js" defer="defer"></script>
</head>
<body>
  <h1>Home</h1>
</body>
</html>

Awesome, thank you. This works wonderfully.