dc7290 / template-ejs-loader

ejs-loader with webpack5 support. Chain it to html-loader and use it with html-webpack-plugin.
MIT License
24 stars 3 forks source link

About inline loader the not get templateParameters of htmlWebpackPlugin #30

Closed jiayisheji closed 1 year ago

jiayisheji commented 1 year ago

Describe the bug Use htmlWebpackPluginTemplateCustomizer can't get HtmlWebpackPlugin.options.templateParameters value.

To Reproduce Steps to reproduce the behavior:

const { htmlWebpackPluginTemplateCustomizer }  = require('template-ejs-loader')
...
module.exports = {
  ...

  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      templateParameters: {
           test: 'This is a test',
           fn(name) { return `This is a name ${name}`}
      },
      template: htmlWebpackPluginTemplateCustomizer({
        templatePath:'./src/index.ejs' // ejs template path 
        htmlLoaderOption:{
          // you can set individual html-loader option here.
          // but preprocessor option is not supported.
        },
        templateEjsLoaderOption:{ // set individual template-ejs-loader option here
          root:'', // this is for example, if not needed, just feel free to delete.
          data:{ // example, too.
            foo:'test' // btw, you can have indivisual data injection for each .ejs file using data option
          }
        }
      }),
    }),
  ]
  ...
}

Expected behavior

<p><%= htmlWebpackPlugin.options.test %></p>
<p><%= htmlWebpackPlugin.options.fn('jiayi') %></p>

Render:

<p>This is a test</p>
<p>This is a name jiayi</p>

Screenshots

Use htmlWebpackPluginTemplateCustomizer

const currentHtmlWebpackPlugin = this._compiler?.options.plugins.filter(
    (plugin) =>
      typeof plugin === 'object' &&
      plugin.options &&
      plugin.options.template &&
      plugin.options.template === this.resource
  )[0]

plugin.options.template always return !${htmlLoader}${htmlLoaderOption}!${templateEjsLoader}${ejsLoaderOption}!${config.templatePath}

The initial configuration path of the template cannot be correct.

Additional context

Reserve the template path to the inline loaders option:

export function htmlWebpackPluginTemplateCustomizer(config: htmlWebpackPluginTemplateCustomizerConfig) {
  const htmlLoader = require.resolve('html-loader') // get html-loader entry path
  const templateEjsLoader =
    process.env.NODE_ENV === 'test' ? resolve(process.cwd(), 'lib/index.js') : require.resolve('template-ejs-loader') // get template-ejs-loader entry path
 //  The actual template path
  config.ejsLoaderOption = Object.assign({}, config.ejsLoaderOption, { templatePath: config.templatePath });

  let htmlLoaderOption = `${customStringify(config.htmlLoaderOption, 'htmlLoaderOption : ')}` // get html-loader option
  let templateEjsLoaderOption = `${customStringify(config.templateEjsLoaderOption, 'templateEjsLoaderOption : ')}` // get template-ejs-loader option
  // Check if option string is empty; (And if it's not, prepend a questionmark '?');
  // This usage is about webpack loader inline, you can check the spec here : https://webpack.js.org/concepts/loaders/#inline
  if (htmlLoaderOption) {
    htmlLoaderOption = `?${htmlLoaderOption}`
  }
  if (templateEjsLoaderOption) {
    templateEjsLoaderOption = `?${templateEjsLoaderOption}`
  }
  // combile loaders/loader options/templatePath then generate customized template name
  return `!${htmlLoader}${htmlLoaderOption}!${templateEjsLoader}${templateEjsLoaderOption}!${config.templatePath}`
}

loader obtains the currentPlugin changes:

// Get the template path from the inline option
  const templatePath = typeof this.query === 'string' && this.query.startsWith('?') && loaderOptions.templatePath;
  const currentHtmlWebpackPlugin = this._compiler?.options.plugins.filter((plugin) => {
    if (typeof plugin === 'object' && plugin.options) {
      const template = templatePath ?? plugin.options.template;
      return typeof template === 'string' && template === this.resource;
    }
    return false;
  })[0];

This is my solution, welcome to exchange ideas.