Detuned
Detuned

Reputation: 3748

Unable to inject data into template with html-webpack-plugin

I've tried to get custom data injected into our .html template using this loader without any success. We've been able to successfully build our assets and have them injected, however, the ability to pass in dynamic data has not worked. Looking at the examples provided in this repo, I don't see how options.title is passed into the template.

I'm using this starter kit, which is quite simple with this plugin: https://github.com/AngularClass/NG6-starter

Here are the versions of the relevant dependencies:

"webpack": "^2.2.1"
"html-webpack-plugin": "^2.29.0"

Copy the relevant section from webpack.config.js:

module.exports = {
  devtool: 'source-map',
  entry: {
    app: [
      'babel-polyfill',
      path.join(__dirname, 'client', 'app/app.js')
    ]
  },
  module: {
    loaders: [
       { test: /\.js$/, exclude: [/app\/lib/, /node_modules/], loader: 'ng-annotate-loader!babel-loader' },
       { test: /\.html$/, loader: 'raw-loader' }, // have also tried with the html-loader
       { test: /\.(scss|sass)$/, loader: 'style-loader!css-loader!sass-loader' },
       { test: /\.css$/, loader: 'style-loader!css-loader' }
    ]
  },
  plugins: [
    // Injects bundles in your index.html instead of wiring all manually.
    // It also adds hash to all injected assets so we don't have problems
    // with cache purging during deployment.
    new HtmlWebpackPlugin({
      template: 'client/index.html',
      // inject: 'body',
      // hash: true,
      title: 'TEST!!!!!!!!!!!',
      options: {
        title: "TEST!!!!!!!!!!!!!*"
      },
      chunks: ['vendor', 'app']
    }),

    // Automatically move all modules defined outside of application directory to vendor bundle.
    // If you are using more complicated project structure, consider to specify common chunks manually.
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      minChunks: module => /node_modules/.test(module.resource)
    })
  ]
};

Template file

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="description" content="NG6-Starter by @AngularClass">
    <link rel="icon" href="data:;base64,iVBORw0KGgo=">
    <base href="/">
  </head>
  <body ng-app="app" ng-strict-di ng-cloak>


  <%= htmlWebpackPlugin.options.title %>

  <%= htmlWebpackPlugin.title %>

  <%= title %>

  <%= '\<\%\= htmlWebpackPlugin.title \%\>' %>

  <%= '\<\%\= htmlWebpackPlugin.options \%\>' %>

  </body>
</html>

Upvotes: 6

Views: 16699

Answers (3)

Anton Egorov
Anton Egorov

Reputation: 1372

You can do the following without extra loaders (at least with [email protected]):

new HtmlWebpackPlugin({
  template: 'index.html',
  templateParameters: {
    title: 'foo',
    content: 'bar'
  }
})
<!doctype html>
<html lang="en">

<head>
  <title><%= title %></title>
</head>

<body>
  <p><%= content %></p>
</body>

</html>

Note that this is EJS syntax, but it works in regular .html files, too.

Upvotes: 6

Michael Jungo
Michael Jungo

Reputation: 32982

The correct option is:

<%= htmlWebpackPlugin.options.title %>

This is EJS syntax. It evaluates the expression and puts the result into the HTML in its place. That means it needs to be in the <head> like so:

<title><%= htmlWebpackPlugin.options.title %></title>

The reason that your template is not working, is because you've configured raw-loader to be used for .html files. That means the template is treated as an HTML file. html-webpack-plugin a fallback ejs loader, which is only used if there's no loader configured for a given file. It's a good idea to use .ejs instead of .html for the template, to not conflict the loaders. See also The template option for other solutions (e.g. if you want to use another template engine).

Rename client/index.html to client/index.ejs.

new HtmlWebpackPlugin({
  template: 'client/index.ejs',
  // inject: 'body',
  // hash: true,
  title: 'TEST!!!!!!!!!!!',
  chunks: ['vendor', 'app']
}),

The repository you linked uses old versions of many things (webpack and html-webpack-plugin for instance) and it appears that the version of html-webpack-plugin does not work with the above configuration. You need to upgrade it with:

npm install --save-dev html-webpack-plugin@latest

Upvotes: 11

Detuned
Detuned

Reputation: 3748

So, the issue is that the html or raw loader is taking control of all of the .html files, so the html-webpack-plugin wasn't able to do what it needed. What you essentially need to do is have the raw or html loader point at everything, as needed, but to exclude the template file passed to html-webpack-plugin.

Reference: https://github.com/jantimon/html-webpack-plugin/issues/747#issuecomment-316804313

Upvotes: 3

Related Questions