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

add support for [hash] in filename #257

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
}

compiler.plugin('make', function (compilation, callback) {
// Remove occurences of '[hash]' in the filename so the child
// compiler does not try to replace it.
var escapedFilename = self.options.filename.replace('[hash]', '');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldnt it be better to replace [ and ] to reduce the chance of collisions and support also other webpack variables?

We could move the escaping to a small file in the library folder which does only the webpack filename escaping and unescaping.

What about [ -> {[{ and ] -> }]} ?

Should still be a valid filename: https://en.wikipedia.org/wiki/Filename


// Compile the template (queued)
compilationPromise = childCompiler.compileTemplate(self.options.template, compiler.context, self.options.filename, compilation)
compilationPromise = childCompiler.compileTemplate(self.options.template, compiler.context, escapedFilename, compilation)
.catch(function (err) {
compilation.errors.push(prettyError(err, compiler.context).toString());
return {
Expand Down Expand Up @@ -149,20 +153,22 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
return self.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
})
.then(function (html) {
var outputFilename = self.options.filename.replace('[hash]', self.childCompilerHash);
// Replace the compilation result with the evaluated html code
compilation.assets[self.options.filename] = {
compilation.assets[outputFilename] = {
source: function () {
return html;
},
size: function () {
return html.length;
}
};
return outputFilename;
})
.then(function () {
.then(function (outputFilename) {
// Let other plugins know that we are done:
return applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', {
html: compilation.assets[self.options.filename],
html: compilation.assets[outputFilename],
plugin: self
});
})
Expand Down
21 changes: 21 additions & 0 deletions spec/BasicSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ 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(outputFileExists).toBe(true);
if (!outputFileExists) {
Expand Down Expand Up @@ -573,6 +581,19 @@ describe('HtmlWebpackPlugin', function () {
}, ['<script src="index_bundle.js"'], 'test.html', done);
});

it('will replace [hash] in the filename with the child compilation hash', function (done) {
testHtmlPlugin({
entry: path.join(__dirname, 'fixtures/index.js'),
output: {
path: OUTPUT_DIR,
filename: 'index_bundle.js'
},
plugins: [new HtmlWebpackPlugin({
filename: 'test-[hash].html'
})]
}, ['<script src="index_bundle.js"'], /test-\S+\.html$/, done);
});

it('allows you to use an absolute output filename', function (done) {
testHtmlPlugin({
entry: path.join(__dirname, 'fixtures/index.js'),
Expand Down
216 changes: 113 additions & 103 deletions spec/CachingSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ if (!global.Promise) {
require('es6-promise').polyfill();
}

var _ = require('lodash');
var path = require('path');
var webpack = require('webpack');
var rm_rf = require('rimraf');
Expand Down Expand Up @@ -39,115 +40,124 @@ function getCompiledModuleCount (statsJson) {
}, 0);
}

describe('HtmlWebpackPluginCaching', function () {
beforeEach(function (done) {
rm_rf(OUTPUT_DIR, done);
});
var baseConfigurations = [
{},
{
filename: 'test-[hash].html'
}
];

it('should compile nothing if no file was changed', function (done) {
var template = path.join(__dirname, 'fixtures/plain.html');
var htmlWebpackPlugin = new HtmlWebpackPlugin({
template: template
baseConfigurations.forEach(function (baseConfiguration) {
describe('HtmlWebpackPluginCaching', function () {
beforeEach(function (done) {
rm_rf(OUTPUT_DIR, done);
});
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change the template file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
return compiler.run();
})
.then(function (stats) {
// Verify that no file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(0);
// Verify that the html was processed only during the inital build
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(1);
// Verify that the child compilation was executed twice
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});

it('should not compile the webpack html file if only a javascript file was changed', function (done) {
var htmlWebpackPlugin = new HtmlWebpackPlugin();
var compiler = setUpCompiler(htmlWebpackPlugin);
var childCompilerHash;
compiler.run()
// Change a js file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(path.join(__dirname, 'fixtures/index.js'), {footer: '//1'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed only during the inital build
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(1);
// Verify that the child compilation was executed only once
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});
it('should compile nothing if no file was changed', function (done) {
var template = path.join(__dirname, 'fixtures/plain.html');
var htmlWebpackPlugin = new HtmlWebpackPlugin(_.assign(baseConfiguration, {
template: template
}));
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change the template file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
return compiler.run();
})
.then(function (stats) {
// Verify that no file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(0);
// Verify that the html was processed only during the inital build
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(1);
// Verify that the child compilation was executed twice
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});

it('should compile the webpack html file even if only a javascript file was changed if caching is disabled', function (done) {
var htmlWebpackPlugin = new HtmlWebpackPlugin({
cache: false
it('should not compile the webpack html file if only a javascript file was changed', function (done) {
var htmlWebpackPlugin = new HtmlWebpackPlugin(baseConfiguration);
var compiler = setUpCompiler(htmlWebpackPlugin);
var childCompilerHash;
compiler.run()
// Change a js file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(path.join(__dirname, 'fixtures/index.js'), {footer: '//1'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed only during the inital build
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(1);
// Verify that the child compilation was executed only once
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});

it('should compile the webpack html file even if only a javascript file was changed if caching is disabled', function (done) {
var htmlWebpackPlugin = new HtmlWebpackPlugin(_.assign(baseConfiguration, {
cache: false
}));
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change a js file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(path.join(__dirname, 'fixtures/index.js'), {footer: '//1'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed on every run
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(2);
// Verify that the child compilation was executed only once
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change a js file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(path.join(__dirname, 'fixtures/index.js'), {footer: '//1'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed on every run
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(2);
// Verify that the child compilation was executed only once
expect(htmlWebpackPlugin.childCompilerHash)
.toBe(childCompilerHash);
})
.then(done);
});

it('should compile the webpack html if the template file was changed', function (done) {
var template = path.join(__dirname, 'fixtures/plain.html');
var htmlWebpackPlugin = new HtmlWebpackPlugin({
template: template
it('should compile the webpack html if the template file was changed', function (done) {
var template = path.join(__dirname, 'fixtures/plain.html');
var htmlWebpackPlugin = new HtmlWebpackPlugin(_.assign(baseConfiguration, {
template: template
}));
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change the template file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(template, {footer: '<!-- 1 -->'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed twice
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(2);
// Verify that the child compilation was executed twice
expect(htmlWebpackPlugin.childCompilerHash)
.not.toBe(childCompilerHash);
})
.then(done);
});
var childCompilerHash;
var compiler = setUpCompiler(htmlWebpackPlugin);
compiler.run()
// Change the template file and compile again
.then(function () {
childCompilerHash = htmlWebpackPlugin.childCompilerHash;
compiler.simulateFileChange(template, {footer: '<!-- 1 -->'});
return compiler.run();
})
.then(function (stats) {
// Verify that only one file was built
expect(getCompiledModuleCount(stats.toJson()))
.toBe(1);
// Verify that the html was processed twice
expect(htmlWebpackPlugin.evaluateCompilationResult.calls.count())
.toBe(2);
// Verify that the child compilation was executed twice
expect(htmlWebpackPlugin.childCompilerHash)
.not.toBe(childCompilerHash);
})
.then(done);
});
});