AsyncModuleRuntimeModule.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const RuntimeGlobals = require("../RuntimeGlobals");
  6. const Template = require("../Template");
  7. const HelperRuntimeModule = require("./HelperRuntimeModule");
  8. /** @typedef {import("../Compilation")} Compilation */
  9. class AsyncModuleRuntimeModule extends HelperRuntimeModule {
  10. /**
  11. * @param {boolean=} deferInterop if defer import is used.
  12. */
  13. constructor(deferInterop = false) {
  14. super("async module");
  15. /** @type {boolean} */
  16. this._deferInterop = deferInterop;
  17. }
  18. /**
  19. * Generates runtime code for this runtime module.
  20. * @returns {string | null} runtime code
  21. */
  22. generate() {
  23. const compilation = /** @type {Compilation} */ (this.compilation);
  24. const { runtimeTemplate } = compilation;
  25. const fn = RuntimeGlobals.asyncModule;
  26. const defer = this._deferInterop;
  27. return Template.asString([
  28. 'var hasSymbol = typeof Symbol === "function";',
  29. 'var webpackQueues = hasSymbol ? Symbol("webpack queues") : "__webpack_queues__";',
  30. `var webpackExports = ${
  31. defer ? `${RuntimeGlobals.asyncModuleExportSymbol}= ` : ""
  32. }hasSymbol ? Symbol("webpack exports") : "${RuntimeGlobals.exports}";`,
  33. 'var webpackError = hasSymbol ? Symbol("webpack error") : "__webpack_error__";',
  34. defer
  35. ? Template.asString([
  36. `var webpackDone = ${RuntimeGlobals.asyncModuleDoneSymbol} = hasSymbol ? Symbol("webpack done") : "__webpack_done__";`,
  37. `var webpackDefer = ${RuntimeGlobals.deferredModuleAsyncTransitiveDependenciesSymbol} = hasSymbol ? Symbol("webpack defer") : "__webpack_defer__";`,
  38. `${RuntimeGlobals.deferredModuleAsyncTransitiveDependencies} = ${runtimeTemplate.basicFunction(
  39. "asyncDeps",
  40. [
  41. Template.indent([
  42. "var hasUnresolvedAsyncSubgraph = asyncDeps.some((id) => {",
  43. Template.indent([
  44. "var cache = __webpack_module_cache__[id];",
  45. "return !cache || cache[webpackDone] === false;"
  46. ]),
  47. "});",
  48. "if (hasUnresolvedAsyncSubgraph) {",
  49. Template.indent([
  50. "return ({ then(onFulfilled, onRejected) { return Promise.all(asyncDeps.map(__webpack_require__)).then(onFulfilled, onRejected) } })"
  51. ]),
  52. "}"
  53. ])
  54. ]
  55. )}`
  56. ])
  57. : "",
  58. `var resolveQueue = ${runtimeTemplate.basicFunction("queue", [
  59. "if(queue && queue.d < 1) {",
  60. Template.indent([
  61. "queue.d = 1;",
  62. `queue.forEach(${runtimeTemplate.expressionFunction(
  63. "fn.r--",
  64. "fn"
  65. )});`,
  66. `queue.forEach(${runtimeTemplate.expressionFunction(
  67. "fn.r-- ? fn.r++ : fn()",
  68. "fn"
  69. )});`
  70. ]),
  71. "}"
  72. ])}`,
  73. `var wrapDeps = ${runtimeTemplate.returningFunction(
  74. `deps.map(${runtimeTemplate.basicFunction("dep", [
  75. 'if(dep !== null && typeof dep === "object") {',
  76. Template.indent([
  77. defer
  78. ? Template.asString([
  79. "if(!dep[webpackQueues] && dep[webpackDefer]) {",
  80. Template.indent([
  81. `var asyncDeps = ${RuntimeGlobals.deferredModuleAsyncTransitiveDependencies}(dep[webpackDefer]);`,
  82. "if (asyncDeps) {",
  83. Template.indent([
  84. "var d = dep;",
  85. "dep = {",
  86. Template.indent([
  87. "then(onFulfilled, onRejected) {",
  88. Template.indent([
  89. `asyncDeps.then(${runtimeTemplate.returningFunction(
  90. "onFulfilled(d)"
  91. )}, onRejected);`
  92. ]),
  93. "}"
  94. ]),
  95. "};"
  96. ]),
  97. "} else return dep;"
  98. ]),
  99. "}"
  100. ])
  101. : "",
  102. "if(dep[webpackQueues]) return dep;",
  103. "if(dep.then) {",
  104. Template.indent([
  105. "var queue = [];",
  106. "queue.d = 0;",
  107. `dep.then(${runtimeTemplate.basicFunction("r", [
  108. "obj[webpackExports] = r;",
  109. "resolveQueue(queue);"
  110. ])}, ${runtimeTemplate.basicFunction("e", [
  111. "obj[webpackError] = e;",
  112. "resolveQueue(queue);"
  113. ])});`,
  114. "var obj = {};",
  115. defer ? "obj[webpackDefer] = false;" : "",
  116. `obj[webpackQueues] = ${runtimeTemplate.expressionFunction(
  117. "fn(queue)",
  118. "fn"
  119. )};`,
  120. "return obj;"
  121. ]),
  122. "}"
  123. ]),
  124. "}",
  125. "var ret = {};",
  126. `ret[webpackQueues] = ${runtimeTemplate.emptyFunction()};`,
  127. "ret[webpackExports] = dep;",
  128. "return ret;"
  129. ])})`,
  130. "deps"
  131. )};`,
  132. `${fn} = ${runtimeTemplate.basicFunction("module, body, hasAwait", [
  133. "var queue;",
  134. "hasAwait && ((queue = []).d = -1);",
  135. "var depQueues = new Set();",
  136. "var exports = module.exports;",
  137. "var currentDeps;",
  138. "var outerResolve;",
  139. "var reject;",
  140. `var promise = new Promise(${runtimeTemplate.basicFunction(
  141. "resolve, rej",
  142. ["reject = rej;", "outerResolve = resolve;"]
  143. )});`,
  144. "promise[webpackExports] = exports;",
  145. `promise[webpackQueues] = ${runtimeTemplate.expressionFunction(
  146. `queue && fn(queue), depQueues.forEach(fn), promise["catch"](${runtimeTemplate.emptyFunction()})`,
  147. "fn"
  148. )};`,
  149. "module.exports = promise;",
  150. `var handle = ${runtimeTemplate.basicFunction("deps", [
  151. "currentDeps = wrapDeps(deps);",
  152. "var fn;",
  153. `var getResult = ${runtimeTemplate.returningFunction(
  154. `currentDeps.map(${runtimeTemplate.basicFunction("d", [
  155. defer ? "if(d[webpackDefer]) return d;" : "",
  156. "if(d[webpackError]) throw d[webpackError];",
  157. "return d[webpackExports];"
  158. ])})`
  159. )}`,
  160. `var promise = new Promise(${runtimeTemplate.basicFunction(
  161. "resolve",
  162. [
  163. `fn = ${runtimeTemplate.expressionFunction(
  164. "resolve(getResult)",
  165. ""
  166. )};`,
  167. "fn.r = 0;",
  168. `var fnQueue = ${runtimeTemplate.expressionFunction(
  169. "q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn)))",
  170. "q"
  171. )};`,
  172. `currentDeps.map(${runtimeTemplate.expressionFunction(
  173. `${
  174. defer ? "dep[webpackDefer]||" : ""
  175. }dep[webpackQueues](fnQueue)`,
  176. "dep"
  177. )});`
  178. ]
  179. )});`,
  180. "return fn.r ? promise : getResult();"
  181. ])}`,
  182. `var done = ${runtimeTemplate.expressionFunction(
  183. `(err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)${
  184. defer ? ", promise[webpackDone] = true" : ""
  185. }`,
  186. "err"
  187. )}`,
  188. "body(handle, done);",
  189. "queue && queue.d < 0 && (queue.d = 0);"
  190. ])};`
  191. ]);
  192. }
  193. }
  194. module.exports = AsyncModuleRuntimeModule;