javascripthtmlwebpack-4webpack-splitchunkssplitchunksplugin

How to get webpack4 chunkhash value to use in script src inside the html automatically?


How can I get the chunkhash value generated by webpack4 so that I can use it inside my index.html to set properly the script src?

Brief context: Hope it not to be a stupid question because I am completely newcomer in webpack, started to learn today. I know how to config, extract js, css, minify them, and maybe all the very basic operations.

This is my webpack.config.js:

const path = require('path')
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptmizerCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
    entry: './src/index.js',

    output: {
        path: path.resolve('dist'),
        filename: '[chunkhash].bundle.js' // <<<<<<
    },

    mode: 'development',

    optimization: {
        minimizer: [
            new TerserPlugin({}),
            new OptmizerCssAssetsPlugin({})
        ],
        splitChunks: {
            chunks: 'all'
        }
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        cacheDirectory: true
                    }
                }
            },
            {
                test: /\.css$/,
                use: [
                    { loader: MiniCssExtractPlugin.loader },
                    'css-loader'
                ]
            }
        ]
    },

    plugins: [
        new webpack.ProvidePlugin({
            cowsay: 'cowsay-browser'
        }),
        new MiniCssExtractPlugin({
            filename: 'css/[name].css'
        })
    ]
}

The relevant part is in filename: '[chunkhash].bundle.js' that will produce a filename like 6f9e5dd33686783a5ff8.bundle.js.

I can use that name in my html like <script src="dist/6f9e5dd33686783a5ff8.bundle.js"></script> but I would have to change it everytime the code was updated/regenerated.

I was able to use filename: '[name].bundle.js' instead of the chunkhash but it is not good for caching porpouses.

So, is there any way I can get the chunkhash value and use it to set my script src filename in my index.html automatically everytime I build the project?

Any valid advice will be wellcome!


Solution

  • Ok, I found a way.

    I used the plugin below because it let me use my html as a template file. I just had to remove link and script tags and let it insert them in final html that it will generate.

    This is how I done:

    1 - Install html-webpack-plugin

    npm i -D html-webpack-plugin

    2 - Move my /index.html as /src/main.html

    Because my configs will generate a file named index.html. Rename template as main.html avoids possible confusions

    3 - Add it to plugins secion of webpack.config.js

    // ... other imports here ... //
    
    const HtmlPlugin = require('html-webpack-plugin')
    
    module.exports = {
        entry: './src/index.js',
    
        output: {
            path: path.resolve('dist'),
            filename: '[chunkhash].bundle.js' // **** using chunkhash
        },
    
        mode: 'development',
    
        optimization: {
            minimizer: [
                new TerserPlugin({}),
                new OptmizerCssAssetsPlugin({})
            ],
            splitChunks: {
                chunks: 'all' // **** config the WebPack SplitChunksPlugin
            }
        },
    
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            cacheDirectory: true
                        }
                    }
                },
                {
                    test: /\.css$/,
                    use: [
                        { loader: MiniCssExtractPlugin.loader },
                        'css-loader'
                    ]
                }
            ]
        },
    
        plugins: [
            new webpack.ProvidePlugin({
                cowsay: 'cowsay-browser'
            }),
            new MiniCssExtractPlugin({
                filename: 'css/[contenthash].css' // **** using contenthash
            }),
    
    // **** new config: 
            new HtmlPlugin({
                filename: 'index.html',
                template: path.resolve('src', 'main.html')
            })
        ]
    }
    

    4 - That is all!

    Now, when I build my project, my /src/main.html is parsed, all css link tags and script js tags are inserted automatically in a new /dist/index.html file (see below):

    <!DOCTYPE html>
    <!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
    <!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
    <!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
    <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
        <head>
            <meta charset="utf-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <title>Vacapack</title>
            <meta name="description" content="">
            <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- LOOK THIS: //-->
        <link href="css/7358f9abc5c8cea68707.css" rel="stylesheet"></head>
        <body>
            <pre id="caixa"></pre>
        <!-- AND THESE: //-->
        <script type="text/javascript" src="b6183f7997b49195d1f8.bundle.js"></script>
        <script type="text/javascript" src="0e374d6ca9b34e89e18f.bundle.js"></script></body>
    </html>
    

    Hope it can help some one else!