From c43bb4359fe57c241fbd95c2c73f2920d0315317 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Thu, 9 Jun 2016 21:34:46 +0200 Subject: [PATCH 1/2] Add 'html-webpack-plugin-alter-asset-tags' --- index.js | 75 +++++++++++++++++++++++++++++++++++++++-------- spec/BasicSpec.js | 32 ++++++++++++++++++++ 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 40766e7..b86b141 100644 --- a/index.js +++ b/index.js @@ -143,8 +143,15 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { }); }) .then(function (html) { - // Add the stylesheets, scripts and so on to the resulting html - return self.postProcessHtml(html, assets); + // Prepare script and link tags + var assetTags = self.generateAssetTags(assets); + var pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, outputName: self.childCompilationOutputName}; + // Allow plugins to change the assetTag definitions + return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', pluginArgs) + .then(function () { + // Add the stylesheets, scripts and so on to the resulting html + return self.postProcessHtml(html, assets, { body: pluginArgs.body, head: pluginArgs.head }); + }); }) // Allow plugins to change the html after assets are injected .then(function (html) { @@ -259,7 +266,7 @@ HtmlWebpackPlugin.prototype.executeTemplate = function (templateFunction, chunks * * Returns a promise */ -HtmlWebpackPlugin.prototype.postProcessHtml = function (html, assets) { +HtmlWebpackPlugin.prototype.postProcessHtml = function (html, assets, assetTags) { var self = this; if (typeof html !== 'string') { return Promise.reject('Expected html to be a string but got ' + JSON.stringify(html)); @@ -268,7 +275,7 @@ HtmlWebpackPlugin.prototype.postProcessHtml = function (html, assets) { // Inject .then(function () { if (self.options.inject) { - return self.injectAssetsIntoHtml(html, assets); + return self.injectAssetsIntoHtml(html, assets, assetTags); } else { return html; } @@ -449,27 +456,45 @@ HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chu /** * Injects the assets into the given html string */ -HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets) { +HtmlWebpackPlugin.prototype.generateAssetTags = function (assets, applyPluginsAsyncWaterfall) { // Turn script files into script tags var scripts = assets.js.map(function (scriptPath) { - return ''; + return { + tagName: 'script', + closeTag: true, + attributes: { + type: 'text/javascript', + src: scriptPath + } + }; }); // Make tags self-closing in case of xhtml - var xhtml = this.options.xhtml ? '/' : ''; + var selfClosingTag = !!this.options.xhtml; // Turn css files into link tags var styles = assets.css.map(function (stylePath) { - return ''; + return { + tagName: 'link', + selfClosingTag: selfClosingTag, + attributes: { + href: stylePath, + rel: 'stylesheet' + } + }; }); - // Injections - var htmlRegExp = /(]*>)/i; + // Injection targets var head = []; - var headRegExp = /(<\/head>)/i; var body = []; - var bodyRegExp = /(<\/body>)/i; // If there is a favicon present, add it to the head if (assets.favicon) { - head.push(''); + head.push({ + tagName: 'link', + selfClosingTag: selfClosingTag, + attributes: { + rel: 'shortcut icon', + href: assets.favicon + } + }); } // Add styles to the head head = head.concat(styles); @@ -479,6 +504,18 @@ HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets) { } else { body = body.concat(scripts); } + return {head: head, body: body}; +}; + +/** + * Injects the assets into the given html string + */ +HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets, assetTags) { + var htmlRegExp = /(]*>)/i; + var headRegExp = /(<\/head>)/i; + var bodyRegExp = /(<\/body>)/i; + var body = assetTags.body.map(this.createHtmlTag); + var head = assetTags.head.map(this.createHtmlTag); if (body.length) { if (bodyRegExp.test(html)) { @@ -533,6 +570,18 @@ HtmlWebpackPlugin.prototype.appendHash = function (url, hash) { return url + (url.indexOf('?') === -1 ? '?' : '&') + hash; }; +/** + * Turn a tag definition into a html string + */ +HtmlWebpackPlugin.prototype.createHtmlTag = function (tagDefinition) { + var attributes = Object.keys(tagDefinition.attributes || {}).map(function (attributeName) { + return attributeName + '="' + tagDefinition.attributes[attributeName] + '"'; + }); + return '<' + [tagDefinition.tagName].concat(attributes).join(' ') + (tagDefinition.selfClosingTag ? '/' : '') + '>' + + (tagDefinition.innerHTML || '') + + (tagDefinition.closeTag ? '' : ''); +}; + /** * Helper to return the absolute template path with a fallback loader */ diff --git a/spec/BasicSpec.js b/spec/BasicSpec.js index 9034081..abb2488 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -717,6 +717,38 @@ describe('HtmlWebpackPlugin', function () { ['Public path is https://cdn.com'], null, done); }); + it('fires the html-webpack-plugin-alter-asset-tags event', function (done) { + var eventFired = false; + var examplePlugin = { + apply: function (compiler) { + compiler.plugin('compilation', function (compilation) { + compilation.plugin('html-webpack-plugin-alter-asset-tags', function (object, callback) { + expect(typeof object.body).toBe('object'); + expect(typeof object.head).toBe('object'); + eventFired = true; + callback(); + }); + }); + } + }; + testHtmlPlugin({ + entry: { + app: path.join(__dirname, 'fixtures/index.js') + }, + output: { + path: OUTPUT_DIR, + filename: '[name]_bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin(), + examplePlugin + ] + }, [], null, function () { + expect(eventFired).toBe(true); + done(); + }); + }); + it('fires the html-webpack-plugin-before-html-processing event', function (done) { var eventFired = false; var examplePlugin = { From 86badc3d6e6ae15035d9463a88817dd6488907f3 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Fri, 10 Jun 2016 14:11:01 +0200 Subject: [PATCH 2/2] Add documentation for `html-webpack-plugin-alter-asset-tags` --- CHANGELOG.md | 4 ++++ README.md | 1 + index.js | 4 ++-- package.json | 2 +- spec/BasicSpec.js | 2 +- spec/CachingSpec.js | 2 +- spec/ExampleSpec.js | 2 +- 7 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c2269c..cc72775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Change History ============== +v2.21.0 +---- +* Add `html-webpack-plugin-alter-asset-tags` event to allow plugins to adjust the script/link tags + v2.20.0 ---- * Exclude chunks works now even if combined with dependency sort diff --git a/README.md b/README.md index 9b33aeb..7c4051d 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,7 @@ Asnyc: * `html-webpack-plugin-before-html-generation` * `html-webpack-plugin-before-html-processing` + * `html-webpack-plugin-alter-asset-tags` * `html-webpack-plugin-after-html-processing` * `html-webpack-plugin-after-emit` diff --git a/index.js b/index.js index b86b141..8d5b189 100644 --- a/index.js +++ b/index.js @@ -145,7 +145,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { .then(function (html) { // Prepare script and link tags var assetTags = self.generateAssetTags(assets); - var pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, outputName: self.childCompilationOutputName}; + var pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, chunks: chunks, outputName: self.childCompilationOutputName}; // Allow plugins to change the assetTag definitions return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', pluginArgs) .then(function () { @@ -456,7 +456,7 @@ HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chu /** * Injects the assets into the given html string */ -HtmlWebpackPlugin.prototype.generateAssetTags = function (assets, applyPluginsAsyncWaterfall) { +HtmlWebpackPlugin.prototype.generateAssetTags = function (assets) { // Turn script files into script tags var scripts = assets.js.map(function (scriptPath) { return { diff --git a/package.json b/package.json index e61e341..e099d15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "html-webpack-plugin", - "version": "2.20.0", + "version": "2.21.0", "description": "Simplifies creation of HTML files to serve your webpack bundles", "main": "index.js", "files": [ diff --git a/spec/BasicSpec.js b/spec/BasicSpec.js index abb2488..330bc1d 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -20,7 +20,7 @@ var HtmlWebpackPlugin = require('../index.js'); var OUTPUT_DIR = path.join(__dirname, '../dist'); -jasmine.getEnv().defaultTimeoutInterval = 10000; +jasmine.getEnv().defaultTimeoutInterval = 30000; function testHtmlPlugin (webpackConfig, expectedResults, outputFile, done, expectErrors, expectWarnings) { outputFile = outputFile || 'index.html'; diff --git a/spec/CachingSpec.js b/spec/CachingSpec.js index cc47bdf..7751a50 100644 --- a/spec/CachingSpec.js +++ b/spec/CachingSpec.js @@ -18,7 +18,7 @@ var HtmlWebpackPlugin = require('../index.js'); var OUTPUT_DIR = path.join(__dirname, '../dist'); -jasmine.getEnv().defaultTimeoutInterval = 10000; +jasmine.getEnv().defaultTimeoutInterval = 30000; function setUpCompiler (htmlWebpackPlugin) { spyOn(htmlWebpackPlugin, 'evaluateCompilationResult').and.callThrough(); diff --git a/spec/ExampleSpec.js b/spec/ExampleSpec.js index 98e79a7..29220a2 100644 --- a/spec/ExampleSpec.js +++ b/spec/ExampleSpec.js @@ -20,7 +20,7 @@ var webpackMajorVersion = require('webpack/package.json').version.split('.')[0]; var OUTPUT_DIR = path.join(__dirname, '../dist'); -jasmine.getEnv().defaultTimeoutInterval = 10000; +jasmine.getEnv().defaultTimeoutInterval = 30000; function runExample (exampleName, done) { var examplePath = path.resolve(__dirname, '..', 'examples', exampleName);