Html-webpack-plugin: Unable to render dynamic content from config

Created on 20 Jul 2017  路  37Comments  路  Source: jantimon/html-webpack-plugin

Description

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.

Docs: Template Example

Code Reference: Starter kit

Error Message & Stack Trace

COPY THE ERROR MESSAGE, INCLUDING STACK TRACE HERE

Config

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)
    })
  ]
};

Copy your 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>

Most helpful comment

Use this, only one rule is needed (contrary to what I was saying earlier...)
make sure to install pug-loader rather than pug-html-loader

pug-loader: returns a function
pug-html-loader: returns a string, so it's static and no options can be pass through

{
        test: /.pug$/,
        exclude: ['/node_modules/'],
        use: [
          {
            loader: 'pug-loader',
            query: {
              pretty: true,
              data: {
                global: require('./src/content/global.json'),
                home: require('./src/content/home.json')
              }
            }
          }
        ]
      },

You will still get an error, in hero.pug, but I can't do anything for you there, it's an issue with your code

All 37 comments

I have the same problem, but with .pug file instead html.
Anyone can help us? 馃檹

 new HtmlWebpackPlugin({
      template: 'client/index.html',
      // inject: 'body',
      // hash: true,
      title: 'TEST!!!!!!!!!!!',
})
<!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 %>
  </body>
</html>

Should work

Thanks for the response, @mastilver, but still no luck. For reference, I've downloaded this starter kit to see if I can get it to work: https://github.com/AngularClass/NG6-starter

Yes, there seems to be an issue...

First you can try using { test: /app.*\.html$/, loader: 'raw' }, but it will bring another issue, I will look a bit further on that

I discovered this https://github.com/velenir/html-webpack-template-pug and if you see this specific file https://github.com/Velenir/html-webpack-template-pug/blob/master/mixins.pug he use the htmlWebpackPlugin.options.title in pug template. I did the same thing with no luck!
I don't know where is the problem, i'm going crazy :|

Html Webpack Plugin: Error: Child compilation failed: Module build failed: TypeError: Cannot read property 'options' of undefined

I know exactly what you mean, @giacomoalonzi. I've tried everything under the sun :)

So @FarhadG

webpack.config.js

-       { test: /\.html$/, loader: 'raw' },
+       { test: /app.*\.html$/, loader: 'raw' },

package.json

-    "html-webpack-plugin": "^1.7.0",
+    "html-webpack-plugin": "^2.29.0",

@giacomoalonzi You are next! 馃槃
Can you give me your loaders please

@mastilver thank you man 馃拑

plugins: articles.map(el => {
    const slug = el.title.toLowerCase().split(' ').join('-').split('.').join('')
    return new HtmlWebpackPlugin({
      title: `${el.title}`,
      filename: `news/${slug}.html`,
      template: `./src/views/news/${el.date}.pug`,
      minify: htmlMinifyOptions,
      cache: true,

    })
  }).concat([ // other things

{ test: /\.pug$/, exclude: ['/node_modules/'], use: [ 'html-loader?attrs[]=img:src&attrs[]=video:src&attrs[]=source:src', { loader: 'pug-html-loader', query: { pretty: true, export: false, baseDir: path.resolve(__dirname, 'src/views'), data: { language: currentLang, global: require(`./src/content/${currentLang}/global.json`), home: require(`./src/content/${currentLang}/home.json`), about: require(`./src/content/${currentLang}/about.json`), services: require(`./src/content/${currentLang}/services.json`), careers: require(`./src/content/${currentLang}/careers.json`), journal: require(`./src/content/${currentLang}/journal.json`), news: require(`./src/content/${currentLang}/news.json`), contacts: require(`./src/content/${currentLang}/contacts.json`), articles } } } ] },

First of all did you try following https://github.com/jantimon/html-webpack-plugin/tree/master/examples/jade-loader
I don't know how pug changed a lot since jade

@giacomoalonzi remove html-loader,

html-loader transform html into js which we don't want here

@mastilver , if it's not too much, could you try your suggestion with the boilerplate code I provided above. I'm not sure if I'm doing something wrong but it doesn't seem to work at all...

@mastilver uhm, and which loader I have to use?
this is my initial boilerplate
https://github.com/giacomoalonzi/webpack-webapp/blob/v2/webpack.config.js#L70

edit: I just tried with raw-loader but nothing has changed.

@giacomoalonzi @FarhadG you have the same issue: html-loader is getting in the way of html-webpack-plugin, so you need to setup a regex that match all your html files but your template

In short your template shouldn't be matched by the html-loader

@giacomoalonzi You are using pug, so you just need to setup another loader that only match your template

I don't know what's your file structure, but this should make it obvious:

-       { test: /\.html$/, loader: 'raw' },
+       { test: /app.*\.html$/, loader: 'raw' },

Because my template in not inside the app folder, I can configure my loader to only match html that are inside the app folder and therefor exclude my template

That makes sense, @mastilver. Let me give it a try...

What you mean with "You are using pug, so you just need to setup another loader that only match your template" ?

Whats wrong in this?

{
        test: /\.pug$/,
        exclude: ['/node_modules/'],
        use: [
          'html-loader?attrs[]=img:src&attrs[]=video:src&attrs[]=source:src',
          {
            loader: 'pug-html-loader',
            query: {
              pretty: true,
              export: false,
              baseDir: path.resolve(__dirname, 'src/views'),
            }
          }
        ]
      },

in any case, thank you so much for your time!

if you need pug template elsewhere in your app (if you do import profile from './profile.pug') then keep that one and create a new one for html-webpack-plugin which doesn't use html-loader

uhm... and can you suggest me another loader to do this??

      {
-        test: /\.pug$/,
+        test: /src/views/.+\.pug$/,
        exclude: ['/node_modules/'],
        use: [
          'html-loader',
          {
            loader: 'pug-html-loader',
            query: {
              pretty: true,
              data: {
                global: require('./src/content/global.json'),
                home: require('./src/content/home.json')
              }
            }
          }
        ]
      },
+      {
+        test: test: /src/views/index\.pug$/,
+        exclude: ['/node_modules/'],
+        use: [
+          {
+            loader: 'pug-html-loader',
+            query: {
+              pretty: true,
+              data: {
+                global: require('./src/content/global.json'),
+                home: require('./src/content/home.json')
+              }
+            }
+          }
+        ]
+      },

Something like that

Worked like a charm! You the man, @mastilver. It was truly troubling, going through all of the examples and nothing appeared to work...

I just used the following:

{ test: /\.html$/, loader: 'raw', exclude: /index\.html$/ }

As soon as I have more time on my hand, I will start working on making errors like those more obvious

For reference: Need to investigate if it's possible to get the loaders the template will got through (https://github.com/webpack/webpack/blob/927fc54ed74bd426e1064af9871762b7739566f2/lib/CompatibilityPlugin.js#L48)
If so, check if those loaders includes, throw if that the case

Yeah, the confusing part was that the plugin could, in fact, inject our assets, so it was confusing trying to debug why it wouldn't pass in data. That's what really threw me off...

not work for me @mastilver :( I've fixed your regex with /src\/views\/.+\.pug$/, but if i remove the html-loader i have this error:
You may need an appropriate loader to handle this file type.
but in your example, why you have specified the same configuration twice?

but in your example, why you have specified the same configuration twice?

It's not the same

@mastilver yes I know. So, I replicated your code 1:1 but options still undefined. :|

Can you give me some code, I will check it tomorrow

check this boilerplate
https://github.com/giacomoalonzi/webpack-webapp/blob/v2/webpack.config.js
thank you so much for you time! 馃檹 but we have to solve this issue 馃懐 馃挭

I'm sorry I can't help you!

You gave me a code I already looked at many times, which doesn't contains the changes I told you to apply

@mastilver updated, sorry I forgot to push!

@giacomoalonzi So I don't see your issue, your template is an html one (while you were talking about pug) and I can find Your App Title inside the generated html file

Hi @mastilver what you mean? My templates are .pug not .html. Did you switched to branch-v2 of my webpack-webapp repo?

I was on master indeed...
I know what's the issue, give me 10 mins

no problem @mastilver :)

Use this, only one rule is needed (contrary to what I was saying earlier...)
make sure to install pug-loader rather than pug-html-loader

pug-loader: returns a function
pug-html-loader: returns a string, so it's static and no options can be pass through

{
        test: /.pug$/,
        exclude: ['/node_modules/'],
        use: [
          {
            loader: 'pug-loader',
            query: {
              pretty: true,
              data: {
                global: require('./src/content/global.json'),
                home: require('./src/content/home.json')
              }
            }
          }
        ]
      },

You will still get an error, in hero.pug, but I can't do anything for you there, it's an issue with your code

Works!! With pug-loader work, but i'm not sure if pug-loader accept 'data' like pug-html-loader.
Btw thank you so much @mastilver !!!!!

@mastilver I've refactored whole project with pug-loader.
Data is passed by html-webpack-plugin. Works fantastic!
Thank you so much for your help. You saved my day! 鉂わ笍

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

klinki picture klinki  路  3Comments

GerkinDev picture GerkinDev  路  3Comments

yyx990803 picture yyx990803  路  4Comments

MatthewKosloski picture MatthewKosloski  路  3Comments

NeverwinterMoon picture NeverwinterMoon  路  3Comments