Search code examples
webpackhandlebars.jshtml-webpack-plugin

html-webpack-plugin is not inserting options.title


I am trying to dynamically inject title to html via webpack and html-webpack-plugin. I am using handlebar templating engine. But I have failed to inject title. here is what my webpack config looks like -

/*
|----------------------------------------------
| setting up webpack build process for app
| @author: jahid haque 
| @copyright: mysite, 2019
|----------------------------------------------
*/

const SriPlugin = require('webpack-subresource-integrity');
const Webpack = require('webpack');
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const Optim = {
    runtimeChunk: 'single',
    splitChunks: {
        chunks: 'all',
        maxInitialRequests: Infinity,
        minSize: 0,
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name(module) {
                    const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
                    return `npm.${packageName.replace('@', '')}`;
                },
            },
        },
    },
};

const Module = {
    rules: [
        {
            test: /\.jsx$/,
            exclude: /node_module/,
            use: {
                loader: 'babel-loader',
            },
        },
        {
            test: /\.handlebars$/,
            exclude: /node_module/,
            use: {
                loader: 'handlebars-loader',
            },
        },
    ],
};


module.exports = [

    {
        entry: {
            home: Path.resolve(__dirname, './src/components/home/home.controller.jsx'),
        },
        output: {
            path: Path.resolve(__dirname, './public'),
            filename: Path.join('./js/[name].[contenthash].js'),
            publicPath: '',
            crossOriginLoading: 'anonymous',
        },
        optimization: Optim,

        module: Module,

        plugins: [
            new HtmlWebpackPlugin({
                inject: true,
                hash: true,
                title: 'home page. know how we work',
                template: './src/index.handlebars',
                filename: Path.resolve(__dirname, './public/index.html'),
            }),
            new Webpack.HashedModuleIdsPlugin(),
            new SriPlugin({
                hashFuncNames: ['sha512', 'sha384'],
                enabled: true,
            }),
            new Webpack.NamedChunksPlugin(),
            new CleanWebpackPlugin({
                cleanOnceBeforeBuildPatterns: ['./public/js/'],
            }),
            new WebpackMd5Hash(),
        ],

    },       

    {
        entry: {
            style: Path.resolve(__dirname, './src/scss/app.scss'),
        },
        output: {
            path: Path.resolve(__dirname, './public/css/'),
        },
        optimization: {
            minimizer: [
                new OptimizeCSSAssetsPlugin({}),
            ],
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: 'styles.css',
            }),
        ],
        module: {
            rules: [
                {
                    test: /\.s?css$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'sass-loader',
                    ],
                },
            ],
        },
    },
];

and my htmlWebpack plugin settings are -

new HtmlWebpackPlugin({
   inject: true,
   hash: true,
   title: 'welcome to home page',
   template: './src/index.handlebars',
   filename: 'index.html',
 }),

In my index.handlebars file I am applying this -

<!doctype html>
<html class="no-js" lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Test site | <%= htmlWebpackPlugin.options.title %></title>
        <meta name="description" content="">
        <meta name="keywords" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        {{>partials/head}}
    </head>

    <body class="d-flex flex-column h-100 pt-60">

        {{>partials/nav}}

        <!--[if lt IE 8]>
            <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->

        <main role = 'main' class="flex-shrink-0 min-height-750">
            <div id="welcomeHome"></div>    
        </main>  

        {{>partials/footer}}

    </body>
</html>

and here is package.json

{
  "name": "chefcooks",
  "version": "1.0.0",
  "description": "",
  "main": "index.html",
  "scripts": {
    "start": "webpack-dev-server --mode development --open",
    "dev": "webpack --mode development --watch",
    "build": "webpack --mode production"
  },
  "repository": {
    "type": "git",
    "url": "git+https://[email protected]/hidhaque/chefcooks.git"
  },
  "author": "jahid haque",
  "license": "ISC",
  "homepage": "https://bitbucket.org/hidhaque/chefcooks#readme",
  "devDependencies": {
    "@babel/core": "^7.4.3",
    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
    "@babel/plugin-transform-runtime": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "@babel/preset-es2015": "^7.0.0-beta.53",
    "@babel/preset-react": "^7.0.0",
    "@babel/runtime": "^7.4.3",
    "axios": "^0.18.0",
    "babel-loader": "^8.0.5",
    "babel-plugin-transform-async-to-generator": "^6.24.1",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-polyfill": "^6.26.0",
    "clean-webpack-plugin": "^2.0.1",
    "css-loader": "^2.1.1",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-react": "^7.12.4",
    "handlebars": "^4.1.1",
    "handlebars-loader": "^1.7.1",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.6.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "platform": "^1.3.5",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-loadable": "^5.5.0",
    "sass-loader": "^7.1.0",
    "uglifyjs-webpack-plugin": "^2.1.2",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.3.1",
    "webpack-md5-hash": "0.0.6",
    "webpack-subresource-integrity": "^1.3.2"
  }
}

But the output for title in my index.html remains -

<title>Test title | <%- HtmlWebpackPlugin.options.title %></title>

here is the .babelrc -

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/plugin-transform-runtime", 
        "@babel/plugin-syntax-dynamic-import",
        "transform-async-to-generator",
        [
            "transform-class-properties", 
            { "spec": true }, 
        ]
    ]
}

Could use some help here. I am new to this. Thank you so much.


Solution

  • I've tried to reproduce the issue but I couldn't, insted I made this example and everything is working fine: webpack.config.js

    const path = require('path');
    const WebpackHTMLPlugin = require('html-webpack-plugin');
    
    module.exports = {
        mode: 'development',
        output: {
            path: path.join(__dirname, 'dist'),
            filename: 'app.bundle.js'
        },
        module: {
            rules: [
                {
                    test: /\.handlebars/,
                    use: 'handlebars-loader',
                    exclude: /node_modules/
                }
            ]
        },
        plugins: [
            new WebpackHTMLPlugin({
                inject: true,
                hash: true,
                title: 'My custom title!',
                template: './template.hbs'
            })
        ]
    }
    

    Handlebars template:

    <html>
    <head>
        <meta charset="UTF-8">
        <title>{{ htmlWebpackPlugin.options.title }}</title>
    </head>
    <body>
    
    </body>
    </html>
    

    Just in case I'll show you my package.json:

    {
      "name": "webpack-hbs",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "scripts": {
        "dev": "webpack --config webpack.config"
      },
      "devDependencies": {
        "handlebars-loader": "^1.7.1",
        "html-webpack-plugin": "^3.2.0",
        "webpack": "^4.30.0",
        "webpack-cli": "^3.3.0"
      }
    }
    

    Looking at your code I'm wondering that you're using React, maybe, could you try this code and discuss the ouputs? Hope this answer throw some lights on your issue. Cheers, sigfried.

    UPDATE

    I've managed to resolve the issue, you can see the simple change I've made to index.handlebars. Apparently as pointed out in html-webpack-plugin documentation when you use a different loader it will disable the ejs fallback loader, I'm assuming that beacause of this the <title><%= htmlWebpackPlugin.options %></title> is not working in your case that's why I've changed the template to use Handlebars strings interpolation. I'm still thinking this is weird and maybe I'm missing something else but in any case, this is working right now. Always glad to help, cheers sigfried.