jantimon/html-webpack-plugin

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

OliverJEvans opened this issue ยท 3 comments

Current behaviour ๐Ÿ’ฃ

In v4.0.0. removed a hook called htmlWebpackPluginAlterChunks but without any reasoning or documented replacement (342867e).

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

โ”œโ”€โ”ฌ babel-loader@8.2.5
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ clean-webpack-plugin@4.0.0
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ css-loader@6.7.1
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ css-minimizer-webpack-plugin@3.4.1
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ eslint-webpack-plugin@3.1.1
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ html-webpack-plugin@5.5.0
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ mini-css-extract-plugin@2.6.0
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ postcss-loader@6.2.1
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ sass-loader@12.6.0
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ source-map-loader@3.0.1
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ stylelint-webpack-plugin@3.2.0
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ url-loader@4.1.1
โ”‚ โ”œโ”€โ”ฌ file-loader@6.2.0
โ”‚ โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ vue-loader@16.8.3
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”œโ”€โ”ฌ webpack-cli@4.9.2
โ”‚ โ”œโ”€โ”ฌ @webpack-cli/configtest@1.1.1
โ”‚ โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ”‚ โ””โ”€โ”€ webpack@5.72.1 deduped
โ””โ”€โ”€ webpack@5.72.1
โ””โ”€โ”€ html-webpack-plugin@5.5.0
e9x commented

Commit 342867e 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.

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.

@OliverJEvans I'm not sure if it addresses your concerns, but I created a PR to address mine: #1774. Feel free to test it out and see if it helps you.