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

feat(hooks): Provide static getHook method for access to all html-webpack-plugin hooks #995

Merged
merged 1 commit into from Jul 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Expand Up @@ -308,8 +308,7 @@ function MyPlugin(options) {
MyPlugin.prototype.apply = function (compiler) {
compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
console.log('The compiler is starting a new compilation...');

compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync(
HtmlWebpackPlugin.getHooks(compilation).htmlWebpackPluginAfterHtmlProcessing.tapAsync(
'MyPlugin',
(data, cb) => {
data.html += 'The Magic Footer'
Expand Down
32 changes: 21 additions & 11 deletions index.js
Expand Up @@ -21,14 +21,13 @@ const childCompiler = require('./lib/compiler.js');
const prettyError = require('./lib/errors.js');
const chunkSorter = require('./lib/chunksorter.js');
const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPluginHooks;
const getHtmlWebpackPluginHook = require('./lib/hooks.js').getHtmlWebpackPluginHook;

const fsStatAsync = promisify(fs.stat);
const fsReadFileAsync = promisify(fs.readFile);

class HtmlWebpackPlugin {
/**
* @param {Partial<HtmlWebpackPluginOptions>} options
* @param {Partial<HtmlWebpackPluginOptions>} [options]
*/
constructor (options) {
// Default options
Expand Down Expand Up @@ -60,10 +59,7 @@ class HtmlWebpackPlugin {
this.childCompilationOutputName = undefined;
this.assetJson = undefined;
this.hash = undefined;
/**
* The major version number of this plugin
*/
this.version = 4;
this.version = HtmlWebpackPlugin.version;
}

/**
Expand Down Expand Up @@ -173,7 +169,7 @@ class HtmlWebpackPlugin {
})
// Allow plugins to make changes to the assets before invoking the template
// This only makes sense to use if `inject` is `false`
.then(compilationResult => getHtmlWebpackPluginHook(compilation, 'htmlWebpackPluginBeforeHtmlGeneration').promise({
.then(compilationResult => getHtmlWebpackPluginHooks(compilation).htmlWebpackPluginBeforeHtmlGeneration.promise({
assets: assets,
outputName: self.childCompilationOutputName,
plugin: self
Expand All @@ -186,7 +182,7 @@ class HtmlWebpackPlugin {
// Allow plugins to change the html before assets are injected
.then(html => {
const pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName};
return getHtmlWebpackPluginHook(compilation, 'htmlWebpackPluginBeforeHtmlProcessing').promise(pluginArgs);
return getHtmlWebpackPluginHooks(compilation).htmlWebpackPluginBeforeHtmlProcessing.promise(pluginArgs);
})
.then(result => {
const html = result.html;
Expand All @@ -195,7 +191,7 @@ class HtmlWebpackPlugin {
const assetTags = self.generateHtmlTagObjects(assets);
const pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, outputName: self.childCompilationOutputName};
// Allow plugins to change the assetTag definitions
return getHtmlWebpackPluginHook(compilation, 'htmlWebpackPluginAlterAssetTags').promise(pluginArgs)
return getHtmlWebpackPluginHooks(compilation).htmlWebpackPluginAlterAssetTags.promise(pluginArgs)
.then(result => self.postProcessHtml(html, assets, { body: result.body, head: result.head })
.then(html => _.extend(result, {html: html, assets: assets})));
})
Expand All @@ -204,7 +200,7 @@ class HtmlWebpackPlugin {
const html = result.html;
const assets = result.assets;
const pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName};
return getHtmlWebpackPluginHook(compilation, 'htmlWebpackPluginAfterHtmlProcessing').promise(pluginArgs)
return getHtmlWebpackPluginHooks(compilation).htmlWebpackPluginAfterHtmlProcessing.promise(pluginArgs)
.then(result => result.html);
})
.catch(err => {
Expand All @@ -222,7 +218,7 @@ class HtmlWebpackPlugin {
size: () => html.length
};
})
.then(() => getHtmlWebpackPluginHook(compilation, 'htmlWebpackPluginAfterEmit').promise({
.then(() => getHtmlWebpackPluginHooks(compilation).htmlWebpackPluginAfterEmit.promise({
html: compilation.assets[self.childCompilationOutputName],
outputName: self.childCompilationOutputName,
plugin: self
Expand Down Expand Up @@ -697,4 +693,18 @@ function templateParametersGenerator (compilation, assets, options) {
}
};
}

// Statics:
/**
* The major version number of this plugin
*/
HtmlWebpackPlugin.version = 4;

/**
* A static helper to get the hooks for this plugin
*
* Usage: HtmlWebpackPlugin.getHook(compilation, 'HookName').tap('YourPluginName', () => { ... });
*/
HtmlWebpackPlugin.getHooks = getHtmlWebpackPluginHooks;

module.exports = HtmlWebpackPlugin;
1 change: 0 additions & 1 deletion lib/compiler.js
Expand Up @@ -22,7 +22,6 @@ const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
* for multile HtmlWebpackPlugin instances to improve the compilation performance.
*/
class HtmlWebpackChildCompiler {

constructor () {
/**
* @type {string[]} templateIds
Expand Down
59 changes: 19 additions & 40 deletions lib/hooks.js
Expand Up @@ -5,18 +5,6 @@
'use strict';
/**
* This file provides access to all public htmlWebpackPlugin hooks
*
* Usage:
* ```js
* const getHtmlWebpackPluginHooks = require('html-webpack-plugin/lib/hooks').getHtmlWebpackPluginHooks;
*
* compiler.hooks.compilation.tap('YOUR_PLUGIN_NAME', (compilation) => {
* const htmlWebpackPluginHooks = getHtmlWebpackPluginHooks(compilation);
* htmlWebpackPluginHooks.htmlWebpackPluginAfterEmit.tap('YOUR_PLUGIN_NAME', (pluginArgs) => {
* // your code
* });
* });
* ```
*/

/** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */
Expand Down Expand Up @@ -75,18 +63,23 @@ const AsyncSeriesWaterfallHook = require('tapable').AsyncSeriesWaterfallHook;
}} HtmlWebpackPluginHooks
*/

/**
* @type {WeakMap<WebpackCompilation, HtmlWebpackPluginHooks>}}
*/
const htmlWebpackPluginHooksMap = new WeakMap();

/**
* Returns all public hooks of the html webpack plugin for the given compilation
*
* @param {WebpackCompilation} compilation
* @returns {HtmlWebpackPluginHooks}
*/
function getHtmlWebpackPluginHooks (compilation) {
/** @type {HtmlWebpackPluginHooks} */
const hooks = compilation.hooks;
let hooks = htmlWebpackPluginHooksMap.get(compilation);
// Setup the hooks only once
if (!hooks.htmlWebpackPluginAfterEmit) {
attachHooksToCompilation(compilation);
if (hooks === undefined) {
hooks = createHtmlWebpackPluginHooks();
htmlWebpackPluginHooksMap.set(compilation, hooks);
}
return {
htmlWebpackPluginBeforeHtmlGeneration: hooks.htmlWebpackPluginBeforeHtmlGeneration,
Expand All @@ -101,32 +94,18 @@ function getHtmlWebpackPluginHooks (compilation) {
* Add hooks to the webpack compilation object to allow foreign plugins to
* extend the HtmlWebpackPlugin
*
* @param {WebpackCompilation} compilation
* @returns {HtmlWebpackPluginHooks}
*/
function attachHooksToCompilation (compilation) {
/** @type {HtmlWebpackPluginHooks} */
const hooks = compilation.hooks;
hooks.htmlWebpackPluginBeforeHtmlGeneration = new AsyncSeriesWaterfallHook(['pluginArgs']);
hooks.htmlWebpackPluginBeforeHtmlProcessing = new AsyncSeriesWaterfallHook(['pluginArgs']);
hooks.htmlWebpackPluginAlterAssetTags = new AsyncSeriesWaterfallHook(['pluginArgs']);
hooks.htmlWebpackPluginAfterHtmlProcessing = new AsyncSeriesWaterfallHook(['pluginArgs']);
hooks.htmlWebpackPluginAfterEmit = new AsyncSeriesWaterfallHook(['pluginArgs']);
function createHtmlWebpackPluginHooks () {
return {
htmlWebpackPluginBeforeHtmlGeneration: new AsyncSeriesWaterfallHook(['pluginArgs']),
Copy link
Contributor

Choose a reason for hiding this comment

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

You should consider removing the htmlWebpackPlugin prefix, as it's now already namespace via getHooks.

Copy link
Owner Author

Choose a reason for hiding this comment

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

👍 I'll take a look

htmlWebpackPluginBeforeHtmlProcessing: new AsyncSeriesWaterfallHook(['pluginArgs']),
htmlWebpackPluginAlterAssetTags: new AsyncSeriesWaterfallHook(['pluginArgs']),
htmlWebpackPluginAfterHtmlProcessing: new AsyncSeriesWaterfallHook(['pluginArgs']),
htmlWebpackPluginAfterEmit: new AsyncSeriesWaterfallHook(['pluginArgs'])
};
}

/**
* Small workaround helper to work around https://github.com/Microsoft/TypeScript/issues/1178
* Returns the hook of the given name
*
* @type {
<T extends keyof HtmlWebpackPluginHooks>(compilation: WebpackCompilation, hookName: T) => HtmlWebpackPluginHooks[T]
}
*/
const getHtmlWebpackPluginHook = (compilation, hookName) => {
const hooks = getHtmlWebpackPluginHooks(compilation);
return /** @type {any} */hooks[hookName];
};

module.exports = {
getHtmlWebpackPluginHooks,
getHtmlWebpackPluginHook
getHtmlWebpackPluginHooks
};
2 changes: 1 addition & 1 deletion spec/BasicSpec.js
Expand Up @@ -136,7 +136,7 @@ function getChunksInfoFromStats (stats) {
function tapCompilationEvent (compilation, eventName, handler) {
// Webpack 4 has a new interface
if (compilation.hooks) {
return compilation.hooks[trainCaseToCamelCase(eventName)].tapAsync(
return HtmlWebpackPlugin.getHooks(compilation)[trainCaseToCamelCase(eventName)].tapAsync(
'AsyncPlugin' + tapCompilationEvent.counter++,
handler
);
Expand Down
2 changes: 1 addition & 1 deletion spec/ExampleSpec.js
Expand Up @@ -3,7 +3,7 @@
* and matches them against their dist folder
*/

/* eslint-env jasmine */
/* eslint-env jasmine */
'use strict';

var path = require('path');
Expand Down