plugin.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use strict';
  2. const htmlWebpackPlugin = require('html-webpack-plugin');
  3. const { EVENT, PLUGIN } = require('./constants.js');
  4. const debug = require('./common.js').debug;
  5. const matches = require('./common.js').matches;
  6. const normaliseOptions = require('./config.js');
  7. const shouldAddResourceHints = require('./resource-hints.js').shouldAddResourceHints;
  8. const addInitialChunkResourceHints = require('./initial-chunk-resource-hints.js');
  9. const addAsyncChunkResourceHints = require('./async-chunk-resource-hints.js');
  10. const elements = require('./elements.js');
  11. const customAttributes = require('./custom-attributes.js');
  12. const debugEvent = msg => debug(`${EVENT}: ${msg}`);
  13. const falsySafeConcat = arrays =>
  14. arrays.reduce(
  15. (combined, array) => array ? combined.concat(array) : combined,
  16. []
  17. );
  18. const getHtmlWebpackOptions = pluginArgs =>
  19. (pluginArgs && pluginArgs.plugin && pluginArgs.plugin.options)
  20. ? pluginArgs.plugin.options
  21. : {};
  22. const getCompilationOptions = compilation =>
  23. (compilation && compilation.options) ? compilation.options : {};
  24. class ScriptExtHtmlWebpackPlugin {
  25. constructor (options) {
  26. this.options = normaliseOptions(options);
  27. }
  28. apply (compiler) {
  29. const compile = this.compilationCallback.bind(this);
  30. const emit = this.emitCallback.bind(this);
  31. if (compiler.hooks) {
  32. compiler.hooks.compilation.tap(PLUGIN, compile);
  33. compiler.hooks.emit.tap(PLUGIN, emit);
  34. } else {
  35. compiler.plugin('compilation', compile);
  36. compiler.plugin('emit', emit);
  37. }
  38. }
  39. compilationCallback (compilation) {
  40. const alterAssetTags = this.alterAssetTagsCallback.bind(this, compilation);
  41. if (compilation.hooks) {
  42. const alterAssetTagGroups = compilation.hooks.htmlWebpackPluginAlterAssetTags || htmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups;
  43. alterAssetTagGroups.tap(PLUGIN, alterAssetTags);
  44. } else {
  45. compilation.plugin(EVENT, alterAssetTags);
  46. }
  47. }
  48. alterAssetTagsCallback (compilation, pluginArgs, callback) {
  49. const options = this.options;
  50. const headTagName = pluginArgs.hasOwnProperty('headTags') ? 'headTags' : 'head';
  51. const bodyTagName = pluginArgs.hasOwnProperty('bodyTags') ? 'bodyTags' : 'body';
  52. try {
  53. options.htmlWebpackOptions = getHtmlWebpackOptions(pluginArgs);
  54. options.compilationOptions = getCompilationOptions(compilation);
  55. debugEvent('starting');
  56. if (elements.shouldUpdate(options)) {
  57. debugEvent('replacing <head> <script> elements');
  58. pluginArgs[headTagName] = elements.update(compilation.assets, options, pluginArgs[headTagName]);
  59. debugEvent('replacing <body> <script> elements');
  60. pluginArgs[bodyTagName] = elements.update(compilation.assets, options, pluginArgs[bodyTagName]);
  61. }
  62. if (shouldAddResourceHints(options)) {
  63. debugEvent('adding resource hints');
  64. pluginArgs[headTagName] = falsySafeConcat([
  65. pluginArgs[headTagName],
  66. addInitialChunkResourceHints(options, pluginArgs[headTagName]),
  67. addInitialChunkResourceHints(options, pluginArgs[bodyTagName]),
  68. addAsyncChunkResourceHints(compilation.chunks, options)
  69. ]);
  70. }
  71. if (customAttributes.shouldAdd(options)) {
  72. debugEvent('adding custom attribues to <head> <script> elements');
  73. pluginArgs[headTagName] = customAttributes.add(options, pluginArgs[headTagName]);
  74. debugEvent('adding custom attributes to <body> <script> elements');
  75. pluginArgs[bodyTagName] = customAttributes.add(options, pluginArgs[bodyTagName]);
  76. }
  77. debugEvent('completed');
  78. if (callback) {
  79. callback(null, pluginArgs);
  80. }
  81. } catch (err) {
  82. if (callback) {
  83. callback(err);
  84. } else {
  85. compilation.errors.push(err);
  86. }
  87. }
  88. }
  89. emitCallback (compilation, callback) {
  90. const options = this.options;
  91. if (options.inline.test.length > 0 && options.removeInlinedAssets) {
  92. debug('emit: deleting assets');
  93. Object.keys(compilation.assets).forEach((assetName) => {
  94. if (matches(assetName, options.inline.test)) {
  95. debug(`emit: deleting asset '${assetName}'`);
  96. delete compilation.assets[assetName];
  97. }
  98. });
  99. }
  100. if (callback) {
  101. callback();
  102. }
  103. }
  104. }
  105. module.exports = ScriptExtHtmlWebpackPlugin;