html-webpack-plugin icon indicating copy to clipboard operation
html-webpack-plugin copied to clipboard

Use with Multi-Page Applications

Open christianitis opened this issue 3 years ago • 1 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.

christianitis avatar Feb 11 '22 14:02 christianitis

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
  }),
],

butadpj avatar May 20 '22 04:05 butadpj

@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>

webdiscus avatar Feb 19 '23 14:02 webdiscus

@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.

christianitis avatar Feb 20 '23 15:02 christianitis