From c0b730f25de240a2e95272d8f46ca2a0db62afbc Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Sat, 2 Apr 2016 09:32:56 +0200 Subject: [PATCH 1/3] Support hashes in filenames --- index.js | 10 ++++++---- lib/compiler.js | 21 ++++++++++++++++----- spec/BasicSpec.js | 8 +++++++- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 762d096..aedabde 100644 --- a/index.js +++ b/index.js @@ -48,13 +48,15 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { .catch(function (err) { compilation.errors.push(prettyError(err, compiler.context).toString()); return { - content: self.options.showErrors ? prettyError(err, compiler.context).toJsonHtml() : 'ERROR' + content: self.options.showErrors ? prettyError(err, compiler.context).toJsonHtml() : 'ERROR', + outputName: self.options.filename }; }) .then(function (compilationResult) { // If the compilation change didnt change the cache is valid isCompilationCached = compilationResult.hash && self.childCompilerHash === compilationResult.hash; self.childCompilerHash = compilationResult.hash; + self.childCompilationOutputName = compilationResult.outputName; callback(); return compilationResult.content; }); @@ -150,7 +152,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { }) .then(function (html) { // Replace the compilation result with the evaluated html code - compilation.assets[self.options.filename] = { + compilation.assets[self.childCompilationOutputName] = { source: function () { return html; }, @@ -162,7 +164,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { .then(function () { // Let other plugins know that we are done: return applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', { - html: compilation.assets[self.options.filename], + html: compilation.assets[self.childCompilationOutputName], plugin: self }); }) @@ -349,7 +351,7 @@ HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chu // If a hard coded public path exists use it ? compilation.mainTemplate.getPublicPath({hash: webpackStatsJson.hash}) // If no public path was set get a relative url path - : path.relative(path.resolve(compilation.options.output.path, path.dirname(self.options.filename)), compilation.options.output.path) + : path.relative(path.resolve(compilation.options.output.path, path.dirname(self.childCompilationOutputName)), compilation.options.output.path) .split(path.sep).join('/'); if (publicPath.length && publicPath.substr(-1, 1) !== '/') { diff --git a/lib/compiler.js b/lib/compiler.js index 1577830..cc727d2 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -36,7 +36,8 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou filename: outputFilename, publicPath: compilation.outputOptions.publicPath }; - var cachedAsset = compilation.assets[outputOptions.filename]; + // Store the result of the parent compilation before we start the child compilation + var assetsBeforeCompilation = Object.assign({}, compilation.assets[outputOptions.filename]); // Create an additional child compiler which takes the template // and turns it into an Node.JS html factory. // This allows us to use loaders during the compilation @@ -66,9 +67,17 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou // Compile and return a promise return new Promise(function (resolve, reject) { childCompiler.runAsChild(function (err, entries, childCompilation) { - compilation.assets[outputOptions.filename] = cachedAsset; - if (cachedAsset === undefined) { - delete compilation.assets[outputOptions.filename]; + // Replace [hash] placeholders in filename + var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, { + hash: childCompilation.hash, + chunk: entries[0] + }); + // Restore the parent compilation to the state like it + // was before the child compilation + compilation.assets[outputName] = assetsBeforeCompilation[outputName]; + if (assetsBeforeCompilation[outputName] === undefined) { + // If it wasn't there - delete it + delete compilation.assets[outputName]; } // Resolve / reject the promise if (childCompilation && childCompilation.errors && childCompilation.errors.length) { @@ -82,8 +91,10 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou resolve({ // Hash of the template entry point hash: entries[0].hash, + // Output name + outputName: outputName, // Compiled code - content: childCompilation.assets[outputOptions.filename].source() + content: childCompilation.assets[outputName].source() }); } }); diff --git a/spec/BasicSpec.js b/spec/BasicSpec.js index fc70fd0..32b074d 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -39,7 +39,13 @@ function testHtmlPlugin (webpackConfig, expectedResults, outputFile, done, expec expect(compilationWarnings).toBe(''); } var outputFileExists = fs.existsSync(path.join(OUTPUT_DIR, outputFile)); - expect(outputFileExists).toBe(true); + expect({ + exists: outputFileExists, + filename: outputFile + }).toEqual({ + exists: true, + filename: outputFile + }); if (!outputFileExists) { return done(); } From 765002458bff86a29eef753855e4d530604030f8 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Sat, 2 Apr 2016 14:35:40 +0200 Subject: [PATCH 2/3] Use loadash instead of object assign for old node versions --- lib/compiler.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compiler.js b/lib/compiler.js index cc727d2..326384e 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -6,6 +6,7 @@ */ 'use strict'; var Promise = require('bluebird'); +var _ = require('lodash'); var path = require('path'); var NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin'); var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin'); @@ -37,7 +38,7 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou publicPath: compilation.outputOptions.publicPath }; // Store the result of the parent compilation before we start the child compilation - var assetsBeforeCompilation = Object.assign({}, compilation.assets[outputOptions.filename]); + var assetsBeforeCompilation = _.assign({}, compilation.assets[outputOptions.filename]); // Create an additional child compiler which takes the template // and turns it into an Node.JS html factory. // This allows us to use loaders during the compilation From bfed3a29cc8fc10564c90015751ff0714f6924cb Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 18 Apr 2016 13:00:07 +0200 Subject: [PATCH 3/3] Add support for dynamic filenames --- CHANGELOG.md | 4 ++++ index.js | 22 ++++++++++++++++------ package.json | 2 +- spec/BasicSpec.js | 29 ++++++++++++++++++++++------- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd709da..4fe3ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Change History ============== +v2.16.0 +---- +* Add support for dynamic filenames like index[hash].html + v2.15.0 ---- * Add full unit test coverage for the webpack 2 beta version diff --git a/index.js b/index.js index aedabde..7753670 100644 --- a/index.js +++ b/index.js @@ -109,10 +109,14 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { // Allow plugins to make changes to the assets before invoking the template // This only makes sense to use if `inject` is `false` .then(function (compilationResult) { - return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-generation', {assets: assets, plugin: self}) - .then(function () { - return compilationResult; - }); + return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-generation', { + assets: assets, + outputName: self.childCompilationOutputName, + plugin: self + }) + .then(function () { + return compilationResult; + }); }) // Execute the template .then(function (compilationResult) { @@ -124,7 +128,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { }) // Allow plugins to change the html before assets are injected .then(function (html) { - var pluginArgs = {html: html, assets: assets, plugin: self}; + var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName}; return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', pluginArgs) .then(function () { return pluginArgs.html; @@ -136,7 +140,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { }) // Allow plugins to change the html after assets are injected .then(function (html) { - var pluginArgs = {html: html, assets: assets, plugin: self}; + var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName}; return applyPluginsAsyncWaterfall('html-webpack-plugin-after-html-processing', pluginArgs) .then(function () { return pluginArgs.html; @@ -165,7 +169,13 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { // Let other plugins know that we are done: return applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', { html: compilation.assets[self.childCompilationOutputName], + outputName: self.childCompilationOutputName, plugin: self + }).catch(function (err) { + console.error(err); + return null; + }).then(function () { + return null; }); }) // Let webpack continue with it diff --git a/package.json b/package.json index c67c5c0..b8854bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "html-webpack-plugin", - "version": "2.15.0", + "version": "2.16.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 32b074d..bf8de01 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -38,14 +38,16 @@ function testHtmlPlugin (webpackConfig, expectedResults, outputFile, done, expec } else { expect(compilationWarnings).toBe(''); } + if (outputFile instanceof RegExp) { + var matches = Object.keys(stats.compilation.assets).filter(function (item) { + return outputFile.test(item); + }); + expect(matches.length).toBe(1); + outputFile = matches[0]; + } + expect(outputFile.indexOf('[hash]') === -1).toBe(true); var outputFileExists = fs.existsSync(path.join(OUTPUT_DIR, outputFile)); - expect({ - exists: outputFileExists, - filename: outputFile - }).toEqual({ - exists: true, - filename: outputFile - }); + expect(outputFileExists).toBe(true); if (!outputFileExists) { return done(); } @@ -579,6 +581,19 @@ describe('HtmlWebpackPlugin', function () { }, ['