jantimon/html-webpack-plugin

Control HTML Emit stage

serkanyersen opened this issue · 5 comments

Hi,

I have a plugin that generates a custom manifest about the assets generated by webpack, I also need to embed the finalized manifest into the html.

My problem right now is that contents of the assets are not finalized until the PROCESS_ASSETS_STAGE_OPTIMIZE_HASH stage is done, because some chunks might be altered with the updated hashes. However, html-webpack-plugin is emitting the final HTML at PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE stage.

Which is very early and there is no way to go back to update the HTML generated.

It would be nice if there is a way to control the stage when the HTML is emitted here

{
name: 'HtmlWebpackPlugin',
stage:
/**
* Generate the html after minification and dev tooling is done
*/
webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE
},

If I set this to PROCESS_ASSETS_STAGE_REPORT everything works as expected for me.

is there a way to achieve this without this change? if not can we make stage configurable?

if I locally patch the package to run at PROCESS_ASSETS_STAGE_REPORT

or intercept like this

compilation.hooks.processAssets.intercept({
  register: (tap) => {
    if (tap.name === 'HtmlWebpackPlugin') {
      tap.stage = webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT;
    }
    return tap;
  },
})

would it cause any issues?

We have a similar issue with our plugin that uses HtmlWebpackPlugin as well.
@jantimon, would the fix suggested by @serkanyersen cause any issues?
Thank you!

There was a long discussion about this topic here:

webpack/webpack#11822

in the end @sokra told us to use PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE

maybe we can ask him for advice

I did use the intercept for a while and it worked fine but later on I replaced that logic with the following.

compiler.hooks.compilation.tap(this.constructor.name, compilation => {
  const hooks = this.options.htmlWebpackPlugin.getHooks(compilation);
  hooks.beforeEmit.tap(this.constructor.name, data => {
    // modify HTML
    return data;
  });
});

compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => {
  if (compilation.hooks.processAssets) {
    compilation.hooks.processAssets.tap(
      {
        name: this.constructor.name,
        stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE,
        additionalAssets: true,
      },
      assets => {
        // correct hashes here including modified HTML
      },
    );
  }
});

Which gave me better results without intercepting. hope this helps.

Edit: I made this change because I no longer needed to embed the manifest into the HTML. which resolved my conflict.

Close due webpack/webpack#11822, most often the problem is in other plugins and they use the wrong stage, anyway feel free to feedback