Made before and after "html-processing" events use callback value (#442)

* Used returned value from applyPluginsAsyncWaterfall promise instead of referred object.
* Removed the possibility to alter 'html' and 'assets' in 'html-webpack-plugin-alter-asset-tags'.
* Added warning for non returned result from 'html-webpack-plugin-after-html-processing' and fixed tests.
This commit is contained in:
Andrea Ascari 2016-10-12 14:23:13 +02:00 committed by Jan Nicklas
parent 9757d3df30
commit 4e29b022b8
2 changed files with 184 additions and 17 deletions

View File

@ -63,7 +63,7 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) {
});
compiler.plugin('emit', function (compilation, callback) {
var applyPluginsAsyncWaterfall = Promise.promisify(compilation.applyPluginsAsyncWaterfall, {context: compilation});
var applyPluginsAsyncWaterfall = self.applyPluginsAsyncWaterfall(compilation);
// Get all chunks
var chunks = self.filterChunks(compilation.getStats().toJson(), self.options.chunks, self.options.excludeChunks);
// Sort chunks
@ -137,28 +137,33 @@ 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, outputName: self.childCompilationOutputName};
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', pluginArgs)
.then(function () {
return pluginArgs.html;
});
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', pluginArgs);
})
.then(function (html) {
.then(function (result) {
var html = result.html;
var assets = result.assets;
var chunks = result.chunks;
// Prepare script and link tags
var assetTags = self.generateAssetTags(assets);
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 () {
.then(function (result) {
// Add the stylesheets, scripts and so on to the resulting html
return self.postProcessHtml(html, assets, { body: pluginArgs.body, head: pluginArgs.head });
return self.postProcessHtml(html, assets, { body: result.body, head: result.head })
.then(function (html) {
return _.extend(result, {html: html, assets: assets});
});
});
})
// Allow plugins to change the html after assets are injected
.then(function (html) {
.then(function (result) {
var html = result.html;
var assets = result.assets;
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;
.then(function (result) {
return result.html;
});
})
.catch(function (err) {
@ -612,4 +617,21 @@ HtmlWebpackPlugin.prototype.getAssetFiles = function (assets) {
return files;
};
/**
* Helper to promisify compilation.applyPluginsAsyncWaterfall that returns
* a function that helps to merge given plugin arguments with processed ones
*/
HtmlWebpackPlugin.prototype.applyPluginsAsyncWaterfall = function (compilation) {
var promisedApplyPluginsAsyncWaterfall = Promise.promisify(compilation.applyPluginsAsyncWaterfall, {context: compilation});
return function (eventName, pluginArgs) {
return promisedApplyPluginsAsyncWaterfall(eventName, pluginArgs)
.then(function (result) {
if (!result) {
compilation.warnings.push(new Error('Using html-webpack-plugin-after-html-processing without returning a result is deprecated.'));
}
return _.extend(pluginArgs, result);
});
};
};
module.exports = HtmlWebpackPlugin;

View File

@ -15,6 +15,7 @@ var path = require('path');
var fs = require('fs');
var webpack = require('webpack');
var rimraf = require('rimraf');
var _ = require('lodash');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var HtmlWebpackPlugin = require('../index.js');
@ -746,7 +747,7 @@ describe('HtmlWebpackPlugin', function () {
}, [], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('fires the html-webpack-plugin-before-html-processing event', function (done) {
@ -776,7 +777,7 @@ describe('HtmlWebpackPlugin', function () {
}, [], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('fires the html-webpack-plugin-after-html-processing event', function (done) {
@ -806,7 +807,7 @@ describe('HtmlWebpackPlugin', function () {
}, [], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('fires the html-webpack-plugin-after-emit event', function (done) {
@ -836,7 +837,7 @@ describe('HtmlWebpackPlugin', function () {
}, [], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('allows to modify the html during html-webpack-plugin-after-html-processing event', function (done) {
@ -867,6 +868,150 @@ describe('HtmlWebpackPlugin', function () {
}, ['Injected by plugin'], null, function () {
expect(eventFired).toBe(true);
done();
}, false, true);
});
it('allows to modify sequentially the html during html-webpack-plugin-after-html-processing event by edit the given arguments object', function (done) {
var eventFiredForFirstPlugin = false;
var eventFiredForSecondPlugin = false;
var examplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForFirstPlugin = true;
object.html += 'Injected by first plugin';
callback(null, object);
});
});
}
};
var secondExamplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForSecondPlugin = true;
object.html += ' Injected by second plugin';
callback(null);
});
});
}
};
testHtmlPlugin({
entry: {
app: path.join(__dirname, 'fixtures/index.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
examplePlugin,
secondExamplePlugin
]
}, ['Injected by first plugin Injected by second plugin'], null, function () {
expect(eventFiredForFirstPlugin).toBe(true);
expect(eventFiredForSecondPlugin).toBe(true);
done();
}, false, true);
});
it('allows to modify sequentially the html during html-webpack-plugin-after-html-processing event either by edit the given arguments object or by return a new object in the callback', function (done) {
var eventFiredForFirstPlugin = false;
var eventFiredForSecondPlugin = false;
var examplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForFirstPlugin = true;
var result = _.extend(object, {
html: object.html + 'Injected by first plugin'
});
callback(null, result);
});
});
}
};
var secondExamplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForSecondPlugin = true;
object.html += ' Injected by second plugin';
callback(null);
});
});
}
};
testHtmlPlugin({
entry: {
app: path.join(__dirname, 'fixtures/index.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
examplePlugin,
secondExamplePlugin
]
}, ['Injected by first plugin Injected by second plugin'], null, function () {
expect(eventFiredForFirstPlugin).toBe(true);
expect(eventFiredForSecondPlugin).toBe(true);
done();
}, false, true);
});
it('allows to modify sequentially the html during html-webpack-plugin-after-html-processing event by return a new object in the callback', function (done) {
var eventFiredForFirstPlugin = false;
var eventFiredForSecondPlugin = false;
var examplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForFirstPlugin = true;
var result = _.extend(object, {
html: object.html + 'Injected by first plugin'
});
callback(null, result);
});
});
}
};
var secondExamplePlugin = {
apply: function (compiler) {
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-html-processing', function (object, callback) {
eventFiredForSecondPlugin = true;
var result = _.extend(object, {
html: object.html + ' Injected by second plugin'
});
callback(null, result);
});
});
}
};
testHtmlPlugin({
entry: {
app: path.join(__dirname, 'fixtures/index.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
examplePlugin,
secondExamplePlugin
]
}, ['Injected by first plugin Injected by second plugin'], null, function () {
expect(eventFiredForFirstPlugin).toBe(true);
expect(eventFiredForSecondPlugin).toBe(true);
done();
});
});
@ -899,7 +1044,7 @@ describe('HtmlWebpackPlugin', function () {
}, ['Injected by plugin', '<script type="text/javascript" src="funky-script.js"'], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('allows to modify the html during html-webpack-plugin-before-html-generation event', function (done) {
@ -933,7 +1078,7 @@ describe('HtmlWebpackPlugin', function () {
}, ['<script type="text/javascript" src="funky-script.js"'], null, function () {
expect(eventFired).toBe(true);
done();
});
}, false, true);
});
it('works with commons chunk plugin', function (done) {