Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not working "templateParameters" when prerender-loader used #50

Open
vladlavrik opened this issue Apr 23, 2020 · 3 comments
Open

Not working "templateParameters" when prerender-loader used #50

vladlavrik opened this issue Apr 23, 2020 · 3 comments

Comments

@vladlavrik
Copy link

vladlavrik commented Apr 23, 2020

Hi!
Properties from "templateParameters" do not appear in html when using "prerender-loader".

Minimal code to reproduce:

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'development',
    context: __dirname,
    entry: {
        bundle: './index.js',
    },
    output: {
        path: path.resolve(__dirname, 'build'),
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: `index_.html`,
            template: `!!prerender-loader?string!./index.html`,
            templateParameters: {
                injected: 'foo', // <--------
            },
        }),
    ],
};

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta property="x-injected" content="<%= injected %>">
</head>
<body></body>
</html>

html output

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <meta property="x-injected" content="<%= injected %>">
     <!--                                    ^^^^^^^  -->
</head>
<body>

<div>PRERENDERED CONTENT</div><script src="bundle.js"></script></body></html>```


@vzaidman
Copy link

vzaidman commented May 18, 2020

EDIT: for the updated html-webpack-plugin see: #50 (comment)

the loader node_modules/html-webpack-plugin/lib/loader.js only runs when no other loader is used to load the html and this is what's responsible for the templateParams.

what I did was to copy the file, but remove the lines:

  const allLoadersButThisOne = this.loaders.filter(function (loader) {
    // Loader API changed from `loader.module` to `loader.normal` in Webpack 2.
    return (loader.module || loader.normal) !== module.exports;
  });
  // This loader shouldn't kick in if there is any other loader
  if (allLoadersButThisOne.length > 0) {
    return source;
  }

so the workaround is:

add temporary-template-params-loader.js near webpack.config.js:

/* eslint-disable */
'use strict';

const _ = require('lodash');
const loaderUtils = require('loader-utils');

// temporary loader to ensure templateParams are used.
// see https://github.com/GoogleChromeLabs/prerender-loader/issues/50
module.exports = function (source) {
  if (this.cacheable) {
    this.cacheable();
  }

  // Skip .js files
  if (/\.js$/.test(this.resourcePath)) {
    return source;
  }

  // The following part renders the tempalte with lodash as aminimalistic loader
  //
  // Get templating options
  const options = this.query !== '' ? loaderUtils.parseQuery(this.query) : {};
  const template = _.template(source, _.defaults(options, { variable: 'data' }));
  // Require !!lodash - using !! will disable all loaders (e.g. babel)
  return 'var _ = require(' + loaderUtils.stringifyRequest(this, '!!' + require.resolve('lodash')) + ');' +
    'module.exports = function (templateParams) { with(templateParams) {' +
    // Execute the lodash template
    'return (' + template.source + ')();' +
    '}}';
};

then in webpack.config.js:

in rules:

{
        test: selfPath('src/index.html'),
        use: [
          {
            loader: './temporary-template-params-loader',
          },
          {
            loader: 'prerender-loader',
            options: {
              entry: './src/index.js',
              // notice prerender-loader is used without "string: true"
            },
          },
        ],
      },

plugin:

    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './src/index.html',
      templateParameters: (compilation, params) => {
        Object.assign(params, {myParam});
        return params;
      },
      inject: false,
    }),

@wojtekmaj
Copy link

wojtekmaj commented May 18, 2020

Actually, since jantimon/html-webpack-plugin#972 html-webpack-plugin loader has force flag that skips the very if() you deleted. So it could be as easy as to add force: true. 🤔

@vzaidman
Copy link

right!
it turns out I had an old version (3.2) of the plugin.
in newer versions you can use the loader from html-webpack-plugin:

so in webpack.config.js:

in rules:

{
        test: selfPath('src/index.html'),
        use: [
          {
            loader: 'html-webpack-plugin/lib/loader',
            options: {
              force: true,
            },
          },
          {
            loader: 'prerender-loader',
            options: {
              entry: './src/index.js',
              // notice prerender-loader is used without "string: true"
            },
          },
        ],
      },

plugin:

    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './src/index.html',
      templateParameters: (compilation, params) => {
        Object.assign(params, {myParam});
        return params;
      },
      inject: false,
    }),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants