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

No documented replacement / upgrade path for `htmlWebpackPluginAlterChunks` removed in 4.0.0

Open OliverJEvans opened this issue 2 years ago • 3 comments

Current behaviour 💣

In v4.0.0. removed a hook called htmlWebpackPluginAlterChunks but without any reasoning or documented replacement (https://github.com/jantimon/html-webpack-plugin/commit/342867e1edb7c2a8748b0aca396f160f0b13d42e).

I've picked up an old project and I'm rying to use this hook in a plugin pulled from a (now archived) Shopify Slate theme tool. However without any documented upgrade path I've hit a dead end.

I understand that its been missing for years now, but if theres any documentaiton or thoughts on how it can replaced, I'd be greatly appreciative.

Expected behaviour ☀️

To have a documented replacement for htmlWebpackPluginAlterChunks

Reproduction Example 👾

https://github.com/Shopify/slate/blob/master/packages/slate-tools/tools/webpack/html-webpack-include-chunks.js

  constructor(options) {
    this.options = options;
    this.files = [];
  }

  apply(compiler) {
    compiler.hooks.compilation.tap(
      'htmlWebpackIncludeChunksPlugin',
      this.onCompilation.bind(this),
    );
  }

  onCompilation(compilation) {
    this.compilation = compilation;

    compilation.hooks.htmlWebpackPluginAlterChunks.tap(
      'htmlWebpackIncludeChunksPlugin',
      this.onAlterChunks.bind(this),
    );

    compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tap(
      'htmlWebpackIncludeChunksPlugin',
      this.onBeforeHtmlGeneration.bind(this),
    );
  }

  onAlterChunks(chunks) {
    this.chunks = chunks;
  }

  onBeforeHtmlGeneration(htmlPluginData) {
    const assets = htmlPluginData.assets;
    const publicPath = assets.publicPath;

    this.chunks.forEach((chunk) => {
      const name = chunk.names[0];
      const chunkFiles = []
        .concat(chunk.files)
        .map((chunkFile) => publicPath + chunkFile);

      const css = chunkFiles
        .filter((chunkFile) => /.(css|scss)\.liquid($|\?)/.test(chunkFile))
        .map((chunkFile) => chunkFile.replace(/(\.css)?\.liquid$/, '.css'));

      assets.chunks[name].css = css;
      assets.css = assets.css.concat(css);
    });
  }
}

module.exports = HtmlWebpackIncludeLiquidStylesPlugin;

Environment 🖥

Node.js v16.15.0 darwin 21.5.0 8.5.5

├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├─┬ @webpack-cli/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
└── [email protected]
└── [email protected]

OliverJEvans avatar May 18 '22 22:05 OliverJEvans

Commit 342867e1edb7c2a8748b0aca396f160f0b13d42e has some explanation for this.

BREAKING CHANGES: Pass the entry point names to the custom sort function instead of chunk objects. Removed the alterhtmlWebpackPluginAlterChunks hook. Changed the structure of the assets argument for all hooks.

I am not familiar with how html-webpack-plugin works, however if I had to guess then its because this plugin no longer processes chunks.

e9x avatar Sep 18 '22 00:09 e9x

I am using this plugin and provided a custom sort order via chunksSortMode, and also am using the splitChunks.cacheGroups chunk-splitting optimization provided by Webpack:

const webpackConfig = {
    ...
    entry: {
        main: [
            'babel-polyfill',
            './index.js',
        ],
        splash: ['./web/splash/splash.js'],
    },
    ...
    plugins: [
        ...
        new HtmlWebpackPlugin({
            chunksSortMode: (chunkA, chunkB) => {
                console.log('RORY_DEBUG sorting chunks:', {chunkA, chunkB});
                if (chunkA === 'splash') {
                    return -1;
                }

                return chunkB - chunkA;
            },
        }),
        ...
    ],
    ...
    optimization: {
        runtimeChunk: 'single',
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'initial',
                },
            },
        },
    },
};

The result I see is this:

image

Where the splash entry point is correct sorted above the main entry point, but the other chunks created by optimization.splitChunks.cacheGroups are not sorted. This is breaking what I am trying to do i.e: move the inline splash chunk above the other external chunks that have defer. This in turn is causing my inline blocking chunk to not be executed until the other defer scripts have downloaded and evaluated.

roryabraham avatar Dec 09 '22 19:12 roryabraham

@OliverJEvans I'm not sure if it addresses your concerns, but I created a PR to address mine: https://github.com/jantimon/html-webpack-plugin/pull/1774. Feel free to test it out and see if it helps you.

roryabraham avatar Dec 09 '22 20:12 roryabraham