diff --git a/index.js b/index.js index baacb1ae..bfee97f1 100644 --- a/index.js +++ b/index.js @@ -336,17 +336,20 @@ class HtmlWebpackPlugin { headTags: HtmlTagObject[], bodyTags: HtmlTagObject[] }} assetTags - * @returns {{[key: any]: any}} + * @returns {Promise<{[key: any]: any}>} */ getTemplateParameters (compilation, assets, assetTags) { - if (this.options.templateParameters === false) { - return {}; + const templateParameters = this.options.templateParameters; + if (templateParameters === false) { + return Promise.resolve({}); } - if (typeof this.options.templateParameters === 'function') { - return this.options.templateParameters(compilation, assets, assetTags, this.options); + if (typeof templateParameters === 'function') { + return Promise + .resolve() + .then(() => templateParameters(compilation, assets, assetTags, this.options)); } - if (typeof this.options.templateParameters === 'object') { - return this.options.templateParameters; + if (typeof templateParameters === 'object') { + return Promise.resolve(templateParameters); } throw new Error('templateParameters has to be either a function or an object'); } @@ -372,18 +375,17 @@ class HtmlWebpackPlugin { */ executeTemplate (templateFunction, assets, assetTags, compilation) { // Template processing - const templateParams = this.getTemplateParameters(compilation, assets, assetTags); - /** @type {string|Promise} */ - let html = ''; - try { - html = templateFunction(templateParams); - } catch (e) { - compilation.errors.push(new Error('Template execution failed: ' + e)); - return Promise.reject(e); - } - // If html is a promise return the promise - // If html is a string turn it into a promise - return Promise.resolve().then(() => html); + const templateParamsPromise = this.getTemplateParameters(compilation, assets, assetTags); + return templateParamsPromise.then((templateParams) => { + try { + // If html is a promise return the promise + // If html is a string turn it into a promise + return templateFunction(templateParams); + } catch (e) { + compilation.errors.push(new Error('Template execution failed: ' + e)); + return Promise.reject(e); + } + }); } /** diff --git a/spec/basic.spec.js b/spec/basic.spec.js index e27e86e8..15a15765 100644 --- a/spec/basic.spec.js +++ b/spec/basic.spec.js @@ -1743,6 +1743,26 @@ describe('HtmlWebpackPlugin', () => { }, ['templateParams keys: "foo"'], null, done); }); + it('should allow to set specific template parameters using a async function', done => { + testHtmlPlugin({ + mode: 'production', + entry: path.join(__dirname, 'fixtures/index.js'), + output: { + path: OUTPUT_DIR, + filename: 'index_bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.join(__dirname, 'fixtures/templateParam.js'), + inject: false, + templateParameters: function () { + return Promise.resolve({ 'foo': 'bar' }); + } + }) + ] + }, ['templateParams keys: "foo"'], null, done); + }); + it('should not treat templateContent set to an empty string as missing', done => { testHtmlPlugin({ mode: 'production', diff --git a/typings.d.ts b/typings.d.ts index df4833d6..7d1890a2 100644 --- a/typings.d.ts +++ b/typings.d.ts @@ -24,7 +24,8 @@ interface HtmlWebpackPluginOptions { */ templateParameters: false // Pass an empty object to the template function - | ((compilation: any, assets, assetTags: { headTags: Array, bodyTags: Array }, options: HtmlWebpackPluginOptions) => {}) + | ((compilation: any, assets, assetTags: { headTags: Array, bodyTags: Array }, options: HtmlWebpackPluginOptions) => {[option: string]: any}) + | ((compilation: any, assets, assetTags: { headTags: Array, bodyTags: Array }, options: HtmlWebpackPluginOptions) => Promise<{[option: string]: any}>) | {[option: string]: any} /** * The file to write the HTML to.