hot-middleware.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _utils = require("../../build/utils");
  6. var _nonNullable = require("../../lib/non-nullable");
  7. function isMiddlewareStats(stats) {
  8. for (const key of stats.compilation.entrypoints.keys()){
  9. if ((0, _utils).isMiddlewareFilename(key)) {
  10. return true;
  11. }
  12. }
  13. return false;
  14. }
  15. function statsToJson(stats) {
  16. if (!stats) return {};
  17. return stats.toJson({
  18. all: false,
  19. errors: true,
  20. hash: true,
  21. warnings: true
  22. });
  23. }
  24. class EventStream {
  25. constructor(){
  26. this.clients = new Set();
  27. }
  28. everyClient(fn) {
  29. for (const client of this.clients){
  30. fn(client);
  31. }
  32. }
  33. close() {
  34. this.everyClient((client)=>{
  35. client.close();
  36. });
  37. this.clients.clear();
  38. }
  39. handler(client) {
  40. this.clients.add(client);
  41. client.addEventListener("close", ()=>{
  42. this.clients.delete(client);
  43. });
  44. }
  45. publish(payload) {
  46. this.everyClient((client)=>{
  47. client.send(JSON.stringify(payload));
  48. });
  49. }
  50. }
  51. class WebpackHotMiddleware {
  52. constructor(compilers){
  53. this.eventStream = new EventStream();
  54. this.clientLatestStats = null;
  55. this.middlewareLatestStats = null;
  56. this.serverLatestStats = null;
  57. this.closed = false;
  58. compilers[0].hooks.invalid.tap("webpack-hot-middleware", this.onClientInvalid);
  59. compilers[0].hooks.done.tap("webpack-hot-middleware", this.onClientDone);
  60. compilers[1].hooks.invalid.tap("webpack-hot-middleware", this.onServerInvalid);
  61. compilers[1].hooks.done.tap("webpack-hot-middleware", this.onServerDone);
  62. compilers[2].hooks.done.tap("webpack-hot-middleware", this.onEdgeServerDone);
  63. compilers[2].hooks.invalid.tap("webpack-hot-middleware", this.onEdgeServerInvalid);
  64. }
  65. onClientInvalid = ()=>{
  66. var ref;
  67. if (this.closed || ((ref = this.serverLatestStats) == null ? void 0 : ref.stats.hasErrors())) return;
  68. this.eventStream.publish({
  69. action: "building"
  70. });
  71. };
  72. onClientDone = (statsResult)=>{
  73. var ref;
  74. this.clientLatestStats = {
  75. ts: Date.now(),
  76. stats: statsResult
  77. };
  78. if (this.closed || ((ref = this.serverLatestStats) == null ? void 0 : ref.stats.hasErrors())) return;
  79. this.publishStats("built", statsResult);
  80. };
  81. onServerInvalid = ()=>{
  82. var ref, ref1;
  83. if (!((ref = this.serverLatestStats) == null ? void 0 : ref.stats.hasErrors())) return;
  84. this.serverLatestStats = null;
  85. if ((ref1 = this.clientLatestStats) == null ? void 0 : ref1.stats) {
  86. this.publishStats("built", this.clientLatestStats.stats);
  87. }
  88. };
  89. onServerDone = (statsResult)=>{
  90. if (this.closed) return;
  91. if (statsResult.hasErrors()) {
  92. this.serverLatestStats = {
  93. ts: Date.now(),
  94. stats: statsResult
  95. };
  96. this.publishStats("built", statsResult);
  97. }
  98. };
  99. onEdgeServerInvalid = ()=>{
  100. var ref, ref2;
  101. if (!((ref = this.middlewareLatestStats) == null ? void 0 : ref.stats.hasErrors())) return;
  102. this.middlewareLatestStats = null;
  103. if ((ref2 = this.clientLatestStats) == null ? void 0 : ref2.stats) {
  104. this.publishStats("built", this.clientLatestStats.stats);
  105. }
  106. };
  107. onEdgeServerDone = (statsResult)=>{
  108. if (!isMiddlewareStats(statsResult)) {
  109. this.onServerDone(statsResult);
  110. return;
  111. }
  112. if (statsResult.hasErrors()) {
  113. this.middlewareLatestStats = {
  114. ts: Date.now(),
  115. stats: statsResult
  116. };
  117. this.publishStats("built", statsResult);
  118. }
  119. };
  120. /**
  121. * To sync we use the most recent stats but also we append middleware
  122. * errors. This is because it is possible that middleware fails to compile
  123. * and we still want to show the client overlay with the error while
  124. * the error page should be rendered just fine.
  125. */ onHMR = (client)=>{
  126. if (this.closed) return;
  127. this.eventStream.handler(client);
  128. const [latestStats] = [
  129. this.clientLatestStats,
  130. this.serverLatestStats
  131. ].filter(_nonNullable.nonNullable).sort((statsA, statsB)=>statsB.ts - statsA.ts);
  132. if (latestStats == null ? void 0 : latestStats.stats) {
  133. var ref;
  134. const stats = statsToJson(latestStats.stats);
  135. const middlewareStats = statsToJson((ref = this.middlewareLatestStats) == null ? void 0 : ref.stats);
  136. this.eventStream.publish({
  137. action: "sync",
  138. hash: stats.hash,
  139. errors: [
  140. ...stats.errors || [],
  141. ...middlewareStats.errors || []
  142. ],
  143. warnings: [
  144. ...stats.warnings || [],
  145. ...middlewareStats.warnings || [],
  146. ]
  147. });
  148. }
  149. };
  150. publishStats = (action, statsResult)=>{
  151. const stats = statsResult.toJson({
  152. all: false,
  153. hash: true,
  154. warnings: true,
  155. errors: true
  156. });
  157. this.eventStream.publish({
  158. action: action,
  159. hash: stats.hash,
  160. warnings: stats.warnings || [],
  161. errors: stats.errors || []
  162. });
  163. };
  164. publish = (payload)=>{
  165. if (this.closed) return;
  166. this.eventStream.publish(payload);
  167. };
  168. close = ()=>{
  169. if (this.closed) return;
  170. // Can't remove compiler plugins, so we just set a flag and noop if closed
  171. // https://github.com/webpack/tapable/issues/32#issuecomment-350644466
  172. this.closed = true;
  173. this.eventStream.close();
  174. };
  175. }
  176. exports.WebpackHotMiddleware = WebpackHotMiddleware;
  177. //# sourceMappingURL=hot-middleware.js.map