Html-webpack-plugin: Auto filling chunks

Created on 3 Jun 2018  路  21Comments  路  Source: jantimon/html-webpack-plugin

const config = {

    entry:{
            'datalocation': __dirname + '/src/datalocation.js',
            'reposerver': __dirname + '/src/reposerver.js'
    },
    optimization:{
        splitChunks: {
            chunks:'all',
            name:false
      }
   },
  plugins:[
         new HTMLWebpackPlugin({
                                    template: __dirname + '/src/index.html',
                                    chunks: [*** How to autofill the optimized generated chunks for this entry + only the entry chunk, that will be 0.js + datalocation.js  as per webpack. I dont want to include repocenter.js  ]
                                    filename: datalocation.html',
                                    inject: 'body'
                }),
        new HTMLWebpackPlugin({
                                    template: __dirname + '/src/index.html',
                                    chunks: [*** How to autofill the optimized generated chunks for this entry + only the entry chunk, that will be 0.js + repocenter.js  as per webpack. I dont want to include datalocation.js ]
                                    filename: reposerver.html',
                                    inject: 'body'
                }),

  ]
}

In HTMLWebpaclPlugin under chunks, How to autofill the optimized generated chunks for this entry + only the entry chunk,

The output of web pack
Entrypoint datacenter = 0.js datalocation.js
Entrypoint reposerver = 0.js reposerver.js

In this example there is only one common module, we may have many common modules for a large project with a different set of optimized common modules for each entry

This is similar to #882, but it was closed un resolved.

878 works only for a single entry or it includes all optimized chunks in all html pages

Most helpful comment

Yes, the compilation object provides all the information needed to generate the chunks. However, when returning the modified chunks array I had to emulate the properties of the JSON stats in order to make it work.

The variant I've successfully tried today:

```.js
class ChunksFromEntryPlugin {
apply (compiler) {
compiler.hooks.emit.tap('ChunksFromEntryPlugin', compilation => {
compilation.hooks.htmlWebpackPluginAlterChunks.tap(
'ChunksFromEntryPlugin',
(_, { plugin }) => {
// takes entry name passed via HTMLWebpackPlugin's options
const entry = plugin.options.entry;
const entrypoint = compilation.entrypoints.get(entry);

                return entrypoint.chunks.map(chunk =>
                    ({
                        names: chunk.name ? [chunk.name] : [],
                        files: chunk.files.slice(),
                        size: chunk.modulesSize(),
                        hash: chunk.hash
                    })
                );
            }
        );
    });
}

}
```

Doesn't seem to improve much on the performance compared to using .getStats(), though, at least in the scenario I've tested.

All 21 comments

You are right #882 seems to be not exactly the same as #878.
Sorry @yqz0203 I just thought it's only about split chunks.

@bemineni Right now the feature you are talking about is not available.
We would have to find out:

  • If webpack adds 0.js as an entry module or as an child of datalocation.js
  • At which time during the build process the information about the relation between datalocation.js and 0.js is known

Could you please take a look at that?

I am new to web pack, will try to look into, but I cannot guarantee it. I have a busy schedule with my current bread and butter job.

No problem - I am also very busy so there is no hurry to solve this issue.

You could try to use excludeChunks?

 new HTMLWebpackPlugin({
    template: __dirname + '/src/index.html',
    excludeChunks: ['reposerver'],
    filename: 'datalocation.html',
    inject: 'body'
}),
 new HTMLWebpackPlugin({
    template: __dirname + '/src/index.html',
    excludeChunks: ['datalocation'],
    filename: 'reposerver.html',
    inject: 'body'
}),

@schmkr . We still need to figure out on how to get the optimized chunks to include in the HTML

The one solution I found it's create two separate build for each entry points and run it separately.
I have two builds one for production which generates main index.html with bundles and one for login page.
"build": "webpack --progress --config webpack/prod.js && webpack --progress --config webpack/login.js && cpx \"dist/**/*\"

I had to solve a similar problem for a project I'm working on. We build multiple pages, each with a single entrypoint and one HtmlWebpackPlugin instance to generate the HTML page, while sharing some JS modules and stylesheets between them.

I wanted to let Webpack determine how to split the chunks and pass the dynamically generated chunk names to each HtmlWebpackPlugin instance. I've achieved that with a custom plugin and piggybacking the entrypoint name on the HtmlWebpackPlugin options:

class ChunksFromEntryPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap("ChunksFromEntryPlugin", compilation => {
      const stats = compilation.getStats().toJson();

      compilation.hooks.htmlWebpackPluginAlterChunks.tap(
        "ChunksFromEntryPlugin",
        (_, { plugin }) => {
          // takes entry name passed via HTMLWebpackPlugin's options
          const entry = plugin.options.entry;

          return stats.entrypoints[entry].chunks.map(id =>
            stats.chunks.find(chunk => chunk.id === id)
          );
        }
      );
    });
  }
}

Webpack config:

module.exports = {
  entry: {
    login: 'apps/login.js',
    // some more entries
  },

  plugins: [
    new HtmlWebpackPlugin({
      // `chunks` will be replaced by the "ChunksFromEntryPlugin" below
      chunks: [],
      entry: 'login',
      /* other options */
    }),

    new ChunksFromEntryPlugin()
  ]
};

This implementation still feels quite clunky to me but it works for us. Could this be a good starting point to resolve this issue?

@dmarku wow that's good to know!
According to your example the information available in the webpack emit phase
compilation.getStats() is quite slow.
Could you please check if it is also part of compilation.entrypoints ?

Yes, the compilation object provides all the information needed to generate the chunks. However, when returning the modified chunks array I had to emulate the properties of the JSON stats in order to make it work.

The variant I've successfully tried today:

```.js
class ChunksFromEntryPlugin {
apply (compiler) {
compiler.hooks.emit.tap('ChunksFromEntryPlugin', compilation => {
compilation.hooks.htmlWebpackPluginAlterChunks.tap(
'ChunksFromEntryPlugin',
(_, { plugin }) => {
// takes entry name passed via HTMLWebpackPlugin's options
const entry = plugin.options.entry;
const entrypoint = compilation.entrypoints.get(entry);

                return entrypoint.chunks.map(chunk =>
                    ({
                        names: chunk.name ? [chunk.name] : [],
                        files: chunk.files.slice(),
                        size: chunk.modulesSize(),
                        hash: chunk.hash
                    })
                );
            }
        );
    });
}

}
```

Doesn't seem to improve much on the performance compared to using .getStats(), though, at least in the scenario I've tested.

It would be great if the autofill could be integrated in the HtmlWebpackPlugin.

I'll try to get this into html-webpack-plugin 4:

https://github.com/jantimon/html-webpack-plugin/pull/953

Hi @jantimon,

I am facing same situation where I think HTMLWebpakcPlugin should provide a way to allow including entry chunk + all other needed(vendors/common) chunks generated for that entry through optimization.splitChunks on its own but its just not doing it correctly.

Is it included as part of 4.0.0-alpha or it would be coming through upcoming version?

In another weird scenario:
Plugin is including chunk js multiple times If I don't define "chunks" property in config Object.
Is "chunk" property mandatory in config object for HTMLWebpakcPlugin ?

It has not been included in 4.0.0-alpha yet but I would love to merge the idea of @dmarku into the 4.x branch to fix it

Sorry for the delay - I finally managed to work on other blocking topics.

Autofilling seems to work now.

@dmarku @bemineni @Q-Man @palaniichukdmytro could you please check if the example
https://github.com/jantimon/html-webpack-plugin/pull/1035 covers your case correctly?

@ashoksudani I'll look into that

Thanks @jantimon
Is there any way you can publish these changes as an npm package?

@jantimon Example #1035 matches my use case from the look of it!

Right now, my project that needed this behavior changed its build process and doesn't generate multiple pages anymore, so I won't be able to try this out in practice and provide feedback for the time being.

Aside from that, I think it's a pretty neat feature and I'm excited that this is becoming a thing. Thanks for the work!

Hi @jantimon ,

I tried using latest alpha.2 and it seems I am getting an error while invoking tap for "compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap" it says "Cannot read property 'tap' of undefined", while it was working all good with 3.2.0.

I am getting this error in [email protected] /InterpolateHtmlPlugin.js:26.

Let me know if you want me to debug anything aside.

Hi,

Its failing for other hooks as well e.g. cmpp.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync

compiler.hooks.compilation.tap('FaviconsWebpackPlugin', function (cmpp) { compiler.hooks.compilation.tap('HtmlWebpackPluginHooks', function () { if (!tapped++) { cmpp.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync( 'favicons-webpack-plugin', addFaviconsToHtml ); } }); });

ERROR: : Cannot read property 'tapAsync' of undefined.

@ashoksudani FaviconsWebpackPlugin and InterpolateHtmlPlugin are not compatible to the new hook structure of the alpha version:

https://github.com/jantimon/html-webpack-plugin/blob/webpack-4/README.md#events

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mmjamal picture mmjamal  路  3Comments

amorphius picture amorphius  路  3Comments

lcxfs1991 picture lcxfs1991  路  4Comments

var-bp picture var-bp  路  3Comments

meleyal picture meleyal  路  3Comments