plugin-compat.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. let hookTypes;
  2. const callStyles = {
  3. sync: 'applyPlugins',
  4. syncWaterfall: 'applyPluginsWaterfall',
  5. syncBail: 'applyPluginsBailResult',
  6. sync_map: 'applyPlugins',
  7. asyncWaterfall: 'applyPluginsAsyncWaterfall',
  8. asyncParallel: 'applyPluginsParallel',
  9. asyncSerial: 'applyPluginsAsync',
  10. };
  11. const camelToDash = camel =>
  12. camel.replace(/_/g, '--').replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
  13. const knownPluginRegistrations = {
  14. Compilation: {
  15. needAdditionalPass: ['sync', []],
  16. succeedModule: ['sync', ['module']],
  17. buildModule: ['sync', ['module']],
  18. seal: ['sync', []],
  19. },
  20. Compiler: {
  21. afterCompile: ['asyncSerial', ['compilation']],
  22. afterEnvironment: ['sync', []],
  23. afterPlugins: ['sync', []],
  24. afterResolvers: ['sync', []],
  25. compilation: ['sync', ['compilation', 'params']],
  26. emit: ['asyncSerial', ['compilation']],
  27. make: ['asyncParallel', ['compilation']],
  28. watchRun: ['asyncSerial', ['watcher']],
  29. run: ['asyncSerial', ['compiler']],
  30. },
  31. NormalModuleFactory: {
  32. createModule: ['syncBail', ['data']],
  33. parser: ['sync_map', ['parser', 'parserOptions']],
  34. resolver: ['syncWaterfall', ['nextResolver']],
  35. },
  36. ContextModuleFactory: {
  37. afterResolve: ['asyncWaterfall', ['data']],
  38. },
  39. };
  40. exports.register = (tapable, name, style, args) => {
  41. if (tapable.hooks) {
  42. if (!hookTypes) {
  43. const Tapable = require('tapable');
  44. hookTypes = {
  45. sync: Tapable.SyncHook,
  46. syncWaterfall: Tapable.SyncWaterfallHook,
  47. syncBail: Tapable.SyncBailHook,
  48. asyncWaterfall: Tapable.AsyncWaterfallHook,
  49. asyncParallel: Tapable.AsyncParallelHook,
  50. asyncSerial: Tapable.AsyncSeriesHook,
  51. asyncSeries: Tapable.AsyncSeriesHook,
  52. };
  53. }
  54. if (!tapable.hooks[name]) {
  55. tapable.hooks[name] = new hookTypes[style](args);
  56. }
  57. } else {
  58. if (!tapable.__hardSource_hooks) {
  59. tapable.__hardSource_hooks = {};
  60. }
  61. if (!tapable.__hardSource_hooks[name]) {
  62. tapable.__hardSource_hooks[name] = {
  63. name,
  64. dashName: camelToDash(name),
  65. style,
  66. args,
  67. async: style.startsWith('async'),
  68. map: style.endsWith('_map'),
  69. };
  70. }
  71. if (!tapable.__hardSource_proxy) {
  72. tapable.__hardSource_proxy = {};
  73. }
  74. if (!tapable.__hardSource_proxy[name]) {
  75. if (tapable.__hardSource_hooks[name].map) {
  76. const _forCache = {};
  77. tapable.__hardSource_proxy[name] = {
  78. _forCache,
  79. for: key => {
  80. let hook = _forCache[key];
  81. if (hook) {
  82. return hook;
  83. }
  84. _forCache[key] = {
  85. tap: (...args) => exports.tapFor(tapable, name, key, ...args),
  86. tapPromise: (...args) =>
  87. exports.tapPromiseFor(tapable, name, key, ...args),
  88. call: (...args) => exports.callFor(tapable, name, key, ...args),
  89. promise: (...args) =>
  90. exports.promiseFor(tapable, name, key, ...args),
  91. };
  92. return _forCache[key];
  93. },
  94. tap: (...args) => exports.tapFor(tapable, name, ...args),
  95. tapPromise: (...args) =>
  96. exports.tapPromiseFor(tapable, name, ...args),
  97. call: (...args) => exports.callFor(tapable, name, ...args),
  98. promise: (...args) => exports.promiseFor(tapable, name, ...args),
  99. };
  100. } else {
  101. tapable.__hardSource_proxy[name] = {
  102. tap: (...args) => exports.tap(tapable, name, ...args),
  103. tapPromise: (...args) => exports.tapPromise(tapable, name, ...args),
  104. call: (...args) => exports.call(tapable, name, args),
  105. promise: (...args) => exports.promise(tapable, name, args),
  106. };
  107. }
  108. }
  109. }
  110. };
  111. exports.tap = (tapable, name, reason, callback) => {
  112. if (tapable.hooks) {
  113. tapable.hooks[name].tap(reason, callback);
  114. } else {
  115. if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) {
  116. const registration =
  117. knownPluginRegistrations[tapable.constructor.name][name];
  118. exports.register(tapable, name, registration[0], registration[1]);
  119. }
  120. const dashName = tapable.__hardSource_hooks[name].dashName;
  121. if (tapable.__hardSource_hooks[name].async) {
  122. tapable.plugin(dashName, (...args) => {
  123. const cb = args.pop();
  124. cb(null, callback(...args));
  125. });
  126. } else {
  127. tapable.plugin(dashName, callback);
  128. }
  129. }
  130. };
  131. exports.tapPromise = (tapable, name, reason, callback) => {
  132. if (tapable.hooks) {
  133. tapable.hooks[name].tapPromise(reason, callback);
  134. } else {
  135. if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) {
  136. const registration =
  137. knownPluginRegistrations[tapable.constructor.name][name];
  138. exports.register(tapable, name, registration[0], registration[1]);
  139. }
  140. const dashName = tapable.__hardSource_hooks[name].dashName;
  141. tapable.plugin(dashName, (...args) => {
  142. const cb = args.pop();
  143. return callback(...args).then(value => cb(null, value), cb);
  144. });
  145. }
  146. };
  147. exports.tapAsync = (tapable, name, reason, callback) => {
  148. if (tapable.hooks) {
  149. tapable.hooks[name].tapAsync(reason, callback);
  150. } else {
  151. if (!tapable.__hardSource_hooks || !tapable.__hardSource_hooks[name]) {
  152. const registration =
  153. knownPluginRegistrations[tapable.constructor.name][name];
  154. exports.register(tapable, name, registration[0], registration[1]);
  155. }
  156. const dashName = tapable.__hardSource_hooks[name].dashName;
  157. tapable.plugin(dashName, callback);
  158. }
  159. };
  160. exports.call = (tapable, name, args) => {
  161. if (tapable.hooks) {
  162. const hook = tapable.hooks[name];
  163. return hook.call(...args);
  164. } else {
  165. const dashName = tapable.__hardSource_hooks[name].dashName;
  166. const style = tapable.__hardSource_hooks[name].style;
  167. return tapable[callStyles[style]](...[dashName].concat(args));
  168. }
  169. };
  170. exports.promise = (tapable, name, args) => {
  171. if (tapable.hooks) {
  172. const hook = tapable.hooks[name];
  173. return hook.promise(...args);
  174. } else {
  175. const dashName = tapable.__hardSource_hooks[name].dashName;
  176. const style = tapable.__hardSource_hooks[name].style;
  177. return new Promise((resolve, reject) => {
  178. tapable[callStyles[style]](
  179. ...[dashName].concat(args, (err, value) => {
  180. if (err) {
  181. reject(err);
  182. } else {
  183. resolve(value);
  184. }
  185. }),
  186. );
  187. });
  188. }
  189. };
  190. exports.tapFor = (tapable, name, key, reason, callback) => {
  191. if (tapable.hooks) {
  192. tapable.hooks[name].for(key).tap(reason, callback);
  193. } else {
  194. exports.tap(tapable, name, reason, callback);
  195. }
  196. };
  197. exports.tapPromiseFor = (tapable, name, key, reason, callback) => {
  198. if (tapable.hooks) {
  199. tapable.hooks[name].for(key).tapPromise(reason, callback);
  200. } else {
  201. exports.tapPromise(tapable, name, reason, callback);
  202. }
  203. };
  204. exports.callFor = (tapable, name, key, args) => {
  205. if (tapable.hooks) {
  206. tapable.hooks[name].for(key).call(...args);
  207. } else {
  208. exports.call(tapable, name, args);
  209. }
  210. };
  211. exports.promiseFor = (tapable, name, key, args) => {
  212. if (tapable.hooks) {
  213. tapable.hooks[name].for(key).promise(...args);
  214. } else {
  215. exports.promise(tapable, name, args);
  216. }
  217. };
  218. exports.hooks = tapable => {
  219. if (tapable.hooks) {
  220. return tapable.hooks;
  221. }
  222. if (!tapable.__hardSource_proxy) {
  223. tapable.__hardSource_proxy = {};
  224. }
  225. const registrations = knownPluginRegistrations[tapable.constructor.name];
  226. if (registrations) {
  227. for (const name in registrations) {
  228. const registration = registrations[name];
  229. exports.register(tapable, name, registration[0], registration[1]);
  230. }
  231. }
  232. return tapable.__hardSource_proxy;
  233. };