jantimon/html-webpack-plugin

Ver. 5.6.0: Reference to htmlWebpackPlugin.options.filename in template contains "[name]" instead of actual file name

CarlRaymond opened this issue ยท 7 comments

Current behaviour ๐Ÿ’ฃ

In version 5.6.0, a reference to htmlWebpackPlugin.options.filename within a template file contains the the token [name]. It has not been replaced with the actual filename. In my case, it is ../../Pages/Shared/Bundles/[name].cshtml

Expected behaviour โ˜€๏ธ

In version 5.5.0, the reference has had the [name] token replaced with the filename: ../../Pages/Shared/Bundles/style.cshtml

Reproduction Example ๐Ÿ‘พ

With version 5.6.0 and the configuration below, webpack generates the files main.cshtml, style.cshtml and validation.cshtml, but they are empty. Reverting to version 5.5.0 produces correct contents.

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const Autoprefixer = require('autoprefixer');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const webpack = require('webpack');

module.exports = {

devtool: 'source-map',

entry: {
    style: './css/main.scss',
    main: './js/main.ts',
    validation: {
        import: './js/validation.ts',
        dependOn: 'main'
    }
},

output: {
    path: path.resolve(__dirname, 'wwwroot', 'dist'),
    filename: 'bundles/[name].js',
    publicPath: '/dist/',
    clean: true,
},

watchOptions: {
    ignored: [ '/node_modules/' ]
},

externals: {
    jquery: 'jQuery',
},

resolve: {
    extensions: [".js", ".ts", ".css"],
},

resolveLoader: {
    modules: [
        path.resolve(__dirname, 'js'), // Project-local loaders in js folder
        'node_modules'
    ],
},

module: {
    rules: [
        {
            test: /\.ts$/,
            use: 'ts-loader',
        },
        {
            test: /\.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
        },
        {
            test: /\.(scss)$/,
            use: [
                {
                    loader: MiniCssExtractPlugin.loader, // Extract into separate .css file
                },
                {
                    loader: 'css-loader', // Translates CSS into CommonJS modules
                },
                {
                    loader: 'postcss-loader', // Run postcss actions
                    options: {
                        postcssOptions: {
                            // postcss plugins, can be exported to postcss.config.js
                            plugins: [Autoprefixer]
                            },
                        },
                },
                {
                    loader: 'sass-loader', // compiles Sass to CSS
                    options: {
                        sourceMap: true,
                        sassOptions: {
                            quietDeps: false,
                        }
                    }
                },
            ],
        },
        {
            test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)/i,
            type: 'asset/resource',
            generator: {
                filename: 'fonts/[name][ext][query]',
            },
        },
    ],
},
optimization: {
    splitChunks: {
        chunks: 'async',
        minSize: 20000,
        minRemainingSize: 0,
        minChunks: 1,
        maxAsyncRequests: 30,
        maxInitialRequests: 30,
        enforceSizeThreshold: 50000,
        cacheGroups: {
            defaultVendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: -10,
                reuseExistingChunk: true,
            },
            default: {
                minChunks: 2,
                priority: -20,
                reuseExistingChunk: true,
            },
        },
    },
    minimizer: [
        new CssMinimizerPlugin(),
    ],
},
plugins: [
    new CleanWebpackPlugin(),
    new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery',
        bootstrap: 'bootstrap',
    }),
    new HtmlWebpackPlugin({
        inject: false,
        filename: '../../Pages/Shared/Bundles/[name].cshtml',
        template: './js/bundletemplate.ejs',
    }),
    new MiniCssExtractPlugin({
        filename: 'css/[name].css',
        //ignoreOrder: false,

    }),
],

stats: {
    logging: 'verbose'
}
};

bundletemplate.ejs

<% 
//get bundle file we're currently building. eg site.cshtml
var pathParts = _.split(htmlWebpackPlugin.options.filename, '/')
var file = pathParts[_.size(pathParts)-1]
var fileParts = _.split(file, '.')
var curFile = fileParts[0]

//only show chunks that match current bundle file we're building
var chunkFile = ''
for (var chunk in htmlWebpackPlugin.tags.headTags) {
	var tempChunk = _.replace(htmlWebpackPlugin.tags.headTags[chunk], '</script>', '')
	var pathPartsChunk = _.split(tempChunk, '/') // htmlWebpackPlugin.tags.headTags[chunk], '/')
	var fileChunk = pathPartsChunk[_.size(pathPartsChunk)-1]
	var filePartsChunk = _.split(fileChunk, '.')
	var curChunkFile = filePartsChunk[0]
	
	if (curChunkFile == curFile) {
		chunkFile = htmlWebpackPlugin.tags.headTags[chunk]			
	}
}
%><%=chunkFile%>

Environment ๐Ÿ–ฅ

Node.js v18.16.0
win32 10.0.19045
Waiting for the debugger to disconnect...
9.5.1
website@1.0.0 C:\sandbox\UOE.WebsiteTemplates\content\UOE.Bootstrap5.Razor
โ”œโ”€โ”ฌ clean-webpack-plugin@4.0.0
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ css-loader@7.1.1
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ css-minimizer-webpack-plugin@6.0.0
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ html-webpack-plugin@5.6.0
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ mini-css-extract-plugin@2.9.0
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ postcss-loader@8.1.1
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ sass-loader@14.2.1
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ style-loader@4.0.0
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ ts-loader@9.5.1
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”œโ”€โ”ฌ webpack-cli@5.1.4
โ”‚ โ”œโ”€โ”ฌ @webpack-cli/configtest@2.1.1
โ”‚ โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”‚ โ”œโ”€โ”ฌ @webpack-cli/info@2.0.2
โ”‚ โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”‚ โ”œโ”€โ”ฌ @webpack-cli/serve@2.0.5
โ”‚ โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ”‚ โ””โ”€โ”€ webpack@5.91.0 deduped
โ””โ”€โ”ฌ webpack@5.91.0
โ””โ”€โ”ฌ terser-webpack-plugin@5.3.10
โ””โ”€โ”€ webpack@5.91.0 deduped

website@1.0.0 C:\sandbox\UOE.WebsiteTemplates\content\UOE.Bootstrap5.Razor
โ””โ”€โ”€ html-webpack-plugin@5.6.0

Can you put your example using github? thank you

I just published a minimal example at https://github.com/CarlRaymond/html-webpack-plugin-issue1848 with instructions to make it fail and succeed. Thanks!

I am having the exact same issue.

My attempt at a workaround was to provide a function to filename to generate the string, but the config just contains a reference to the function, instead of the generated string.

This leads to something along the lines of not processing the output filename before generating the values being passed to the templateContent function.

A little bit of research, and this version was the last version that works.

https://www.npmjs.com/package/html-webpack-plugin/v/5.5.3

Sorry, please never rely on htmlWebpackPlugin.options (it will be removed in the next major release, except title), they are lazy evaleted, otherwise we can't calculate contenthash, so you need to find other logic

A little bit of research, and this version was the last version that works.

https://www.npmjs.com/package/html-webpack-plugin/v/5.5.3

it works because we don't make it lazy, so contenthash doesn't work properly and invalidation was broken

Yea, thats cool. Just annoying since the version change between this one and the next is only a patch, but broke some of my code that hasn't changed in like a year.

Feels like the 'lazy' part of that is at least a minor change, instead of patch.

No worries though, I'll go through and make some changes on my project to handle this without depending on the .options interface.