ConsumeSharedRuntimeModule.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("../RuntimeGlobals");
  7. const RuntimeModule = require("../RuntimeModule");
  8. const Template = require("../Template");
  9. const {
  10. parseVersionRuntimeCode,
  11. versionLtRuntimeCode,
  12. rangeToStringRuntimeCode,
  13. satisfyRuntimeCode
  14. } = require("../util/semver");
  15. /** @typedef {import("webpack-sources").Source} Source */
  16. /** @typedef {import("../Chunk")} Chunk */
  17. /** @typedef {import("../Chunk").ChunkId} ChunkId */
  18. /** @typedef {import("../ChunkGraph")} ChunkGraph */
  19. /** @typedef {import("../Compilation")} Compilation */
  20. /** @typedef {import("../Module")} Module */
  21. /** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
  22. /** @typedef {import("./ConsumeSharedModule")} ConsumeSharedModule */
  23. class ConsumeSharedRuntimeModule extends RuntimeModule {
  24. /**
  25. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
  26. */
  27. constructor(runtimeRequirements) {
  28. super("consumes", RuntimeModule.STAGE_ATTACH);
  29. this._runtimeRequirements = runtimeRequirements;
  30. }
  31. /**
  32. * @returns {string | null} runtime code
  33. */
  34. generate() {
  35. const compilation = /** @type {Compilation} */ (this.compilation);
  36. const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
  37. const { runtimeTemplate, codeGenerationResults } = compilation;
  38. /** @type {Record<ChunkId, (string | number)[]>} */
  39. const chunkToModuleMapping = {};
  40. /** @type {Map<string | number, Source>} */
  41. const moduleIdToSourceMapping = new Map();
  42. /** @type {(string | number)[]} */
  43. const initialConsumes = [];
  44. /**
  45. *
  46. * @param {Iterable<Module>} modules modules
  47. * @param {Chunk} chunk the chunk
  48. * @param {(string | number)[]} list list of ids
  49. */
  50. const addModules = (modules, chunk, list) => {
  51. for (const m of modules) {
  52. const module = /** @type {ConsumeSharedModule} */ (m);
  53. const id = chunkGraph.getModuleId(module);
  54. list.push(id);
  55. moduleIdToSourceMapping.set(
  56. id,
  57. codeGenerationResults.getSource(
  58. module,
  59. chunk.runtime,
  60. "consume-shared"
  61. )
  62. );
  63. }
  64. };
  65. for (const chunk of /** @type {Chunk} */ (this.chunk).getAllAsyncChunks()) {
  66. const modules = chunkGraph.getChunkModulesIterableBySourceType(
  67. chunk,
  68. "consume-shared"
  69. );
  70. if (!modules) continue;
  71. addModules(
  72. modules,
  73. chunk,
  74. (chunkToModuleMapping[/** @type {ChunkId} */ (chunk.id)] = [])
  75. );
  76. }
  77. for (const chunk of /** @type {Chunk} */ (
  78. this.chunk
  79. ).getAllInitialChunks()) {
  80. const modules = chunkGraph.getChunkModulesIterableBySourceType(
  81. chunk,
  82. "consume-shared"
  83. );
  84. if (!modules) continue;
  85. addModules(modules, chunk, initialConsumes);
  86. }
  87. if (moduleIdToSourceMapping.size === 0) return null;
  88. return Template.asString([
  89. parseVersionRuntimeCode(runtimeTemplate),
  90. versionLtRuntimeCode(runtimeTemplate),
  91. rangeToStringRuntimeCode(runtimeTemplate),
  92. satisfyRuntimeCode(runtimeTemplate),
  93. `var ensureExistence = ${runtimeTemplate.basicFunction("scopeName, key", [
  94. `var scope = ${RuntimeGlobals.shareScopeMap}[scopeName];`,
  95. `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) throw new Error("Shared module " + key + " doesn't exist in shared scope " + scopeName);`,
  96. "return scope;"
  97. ])};`,
  98. `var findVersion = ${runtimeTemplate.basicFunction("scope, key", [
  99. "var versions = scope[key];",
  100. `var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
  101. "a, b",
  102. ["return !a || versionLt(a, b) ? b : a;"]
  103. )}, 0);`,
  104. "return key && versions[key]"
  105. ])};`,
  106. `var findSingletonVersionKey = ${runtimeTemplate.basicFunction(
  107. "scope, key",
  108. [
  109. "var versions = scope[key];",
  110. `return Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
  111. "a, b",
  112. ["return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;"]
  113. )}, 0);`
  114. ]
  115. )};`,
  116. `var getInvalidSingletonVersionMessage = ${runtimeTemplate.basicFunction(
  117. "scope, key, version, requiredVersion",
  118. [
  119. `return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
  120. ]
  121. )};`,
  122. `var getSingleton = ${runtimeTemplate.basicFunction(
  123. "scope, scopeName, key, requiredVersion",
  124. [
  125. "var version = findSingletonVersionKey(scope, key);",
  126. "return get(scope[key][version]);"
  127. ]
  128. )};`,
  129. `var getSingletonVersion = ${runtimeTemplate.basicFunction(
  130. "scope, scopeName, key, requiredVersion",
  131. [
  132. "var version = findSingletonVersionKey(scope, key);",
  133. "if (!satisfy(requiredVersion, version)) warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
  134. "return get(scope[key][version]);"
  135. ]
  136. )};`,
  137. `var getStrictSingletonVersion = ${runtimeTemplate.basicFunction(
  138. "scope, scopeName, key, requiredVersion",
  139. [
  140. "var version = findSingletonVersionKey(scope, key);",
  141. "if (!satisfy(requiredVersion, version)) " +
  142. "throw new Error(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
  143. "return get(scope[key][version]);"
  144. ]
  145. )};`,
  146. `var findValidVersion = ${runtimeTemplate.basicFunction(
  147. "scope, key, requiredVersion",
  148. [
  149. "var versions = scope[key];",
  150. `var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
  151. "a, b",
  152. [
  153. "if (!satisfy(requiredVersion, b)) return a;",
  154. "return !a || versionLt(a, b) ? b : a;"
  155. ]
  156. )}, 0);`,
  157. "return key && versions[key]"
  158. ]
  159. )};`,
  160. `var getInvalidVersionMessage = ${runtimeTemplate.basicFunction(
  161. "scope, scopeName, key, requiredVersion",
  162. [
  163. "var versions = scope[key];",
  164. 'return "No satisfying version (" + rangeToString(requiredVersion) + ") of shared module " + key + " found in shared scope " + scopeName + ".\\n" +',
  165. `\t"Available versions: " + Object.keys(versions).map(${runtimeTemplate.basicFunction(
  166. "key",
  167. ['return key + " from " + versions[key].from;']
  168. )}).join(", ");`
  169. ]
  170. )};`,
  171. `var getValidVersion = ${runtimeTemplate.basicFunction(
  172. "scope, scopeName, key, requiredVersion",
  173. [
  174. "var entry = findValidVersion(scope, key, requiredVersion);",
  175. "if(entry) return get(entry);",
  176. "throw new Error(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
  177. ]
  178. )};`,
  179. `var warn = ${
  180. compilation.outputOptions.ignoreBrowserWarnings
  181. ? runtimeTemplate.basicFunction("", "")
  182. : runtimeTemplate.basicFunction("msg", [
  183. 'if (typeof console !== "undefined" && console.warn) console.warn(msg);'
  184. ])
  185. };`,
  186. `var warnInvalidVersion = ${runtimeTemplate.basicFunction(
  187. "scope, scopeName, key, requiredVersion",
  188. [
  189. "warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
  190. ]
  191. )};`,
  192. `var get = ${runtimeTemplate.basicFunction("entry", [
  193. "entry.loaded = 1;",
  194. "return entry.get()"
  195. ])};`,
  196. `var init = ${runtimeTemplate.returningFunction(
  197. Template.asString([
  198. "function(scopeName, a, b, c) {",
  199. Template.indent([
  200. `var promise = ${RuntimeGlobals.initializeSharing}(scopeName);`,
  201. `if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c));`,
  202. `return fn(scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c);`
  203. ]),
  204. "}"
  205. ]),
  206. "fn"
  207. )};`,
  208. "",
  209. `var load = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  210. "scopeName, scope, key",
  211. [
  212. "ensureExistence(scopeName, key);",
  213. "return get(findVersion(scope, key));"
  214. ]
  215. )});`,
  216. `var loadFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  217. "scopeName, scope, key, fallback",
  218. [
  219. `return scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) ? get(findVersion(scope, key)) : fallback();`
  220. ]
  221. )});`,
  222. `var loadVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  223. "scopeName, scope, key, version",
  224. [
  225. "ensureExistence(scopeName, key);",
  226. "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
  227. ]
  228. )});`,
  229. `var loadSingleton = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  230. "scopeName, scope, key",
  231. [
  232. "ensureExistence(scopeName, key);",
  233. "return getSingleton(scope, scopeName, key);"
  234. ]
  235. )});`,
  236. `var loadSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  237. "scopeName, scope, key, version",
  238. [
  239. "ensureExistence(scopeName, key);",
  240. "return getSingletonVersion(scope, scopeName, key, version);"
  241. ]
  242. )});`,
  243. `var loadStrictVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  244. "scopeName, scope, key, version",
  245. [
  246. "ensureExistence(scopeName, key);",
  247. "return getValidVersion(scope, scopeName, key, version);"
  248. ]
  249. )});`,
  250. `var loadStrictSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  251. "scopeName, scope, key, version",
  252. [
  253. "ensureExistence(scopeName, key);",
  254. "return getStrictSingletonVersion(scope, scopeName, key, version);"
  255. ]
  256. )});`,
  257. `var loadVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  258. "scopeName, scope, key, version, fallback",
  259. [
  260. `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
  261. "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
  262. ]
  263. )});`,
  264. `var loadSingletonFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  265. "scopeName, scope, key, fallback",
  266. [
  267. `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
  268. "return getSingleton(scope, scopeName, key);"
  269. ]
  270. )});`,
  271. `var loadSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  272. "scopeName, scope, key, version, fallback",
  273. [
  274. `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
  275. "return getSingletonVersion(scope, scopeName, key, version);"
  276. ]
  277. )});`,
  278. `var loadStrictVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  279. "scopeName, scope, key, version, fallback",
  280. [
  281. `var entry = scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) && findValidVersion(scope, key, version);`,
  282. `return entry ? get(entry) : fallback();`
  283. ]
  284. )});`,
  285. `var loadStrictSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
  286. "scopeName, scope, key, version, fallback",
  287. [
  288. `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
  289. "return getStrictSingletonVersion(scope, scopeName, key, version);"
  290. ]
  291. )});`,
  292. "var installedModules = {};",
  293. "var moduleToHandlerMapping = {",
  294. Template.indent(
  295. Array.from(
  296. moduleIdToSourceMapping,
  297. ([key, source]) => `${JSON.stringify(key)}: ${source.source()}`
  298. ).join(",\n")
  299. ),
  300. "};",
  301. initialConsumes.length > 0
  302. ? Template.asString([
  303. `var initialConsumes = ${JSON.stringify(initialConsumes)};`,
  304. `initialConsumes.forEach(${runtimeTemplate.basicFunction("id", [
  305. `${
  306. RuntimeGlobals.moduleFactories
  307. }[id] = ${runtimeTemplate.basicFunction("module", [
  308. "// Handle case when module is used sync",
  309. "installedModules[id] = 0;",
  310. `delete ${RuntimeGlobals.moduleCache}[id];`,
  311. "var factory = moduleToHandlerMapping[id]();",
  312. 'if(typeof factory !== "function") throw new Error("Shared module is not available for eager consumption: " + id);',
  313. `module.exports = factory();`
  314. ])}`
  315. ])});`
  316. ])
  317. : "// no consumes in initial chunks",
  318. this._runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
  319. ? Template.asString([
  320. `var chunkMapping = ${JSON.stringify(
  321. chunkToModuleMapping,
  322. null,
  323. "\t"
  324. )};`,
  325. "var startedInstallModules = {};",
  326. `${
  327. RuntimeGlobals.ensureChunkHandlers
  328. }.consumes = ${runtimeTemplate.basicFunction("chunkId, promises", [
  329. `if(${RuntimeGlobals.hasOwnProperty}(chunkMapping, chunkId)) {`,
  330. Template.indent([
  331. `chunkMapping[chunkId].forEach(${runtimeTemplate.basicFunction(
  332. "id",
  333. [
  334. `if(${RuntimeGlobals.hasOwnProperty}(installedModules, id)) return promises.push(installedModules[id]);`,
  335. "if(!startedInstallModules[id]) {",
  336. `var onFactory = ${runtimeTemplate.basicFunction(
  337. "factory",
  338. [
  339. "installedModules[id] = 0;",
  340. `${
  341. RuntimeGlobals.moduleFactories
  342. }[id] = ${runtimeTemplate.basicFunction("module", [
  343. `delete ${RuntimeGlobals.moduleCache}[id];`,
  344. "module.exports = factory();"
  345. ])}`
  346. ]
  347. )};`,
  348. "startedInstallModules[id] = true;",
  349. `var onError = ${runtimeTemplate.basicFunction("error", [
  350. "delete installedModules[id];",
  351. `${
  352. RuntimeGlobals.moduleFactories
  353. }[id] = ${runtimeTemplate.basicFunction("module", [
  354. `delete ${RuntimeGlobals.moduleCache}[id];`,
  355. "throw error;"
  356. ])}`
  357. ])};`,
  358. "try {",
  359. Template.indent([
  360. "var promise = moduleToHandlerMapping[id]();",
  361. "if(promise.then) {",
  362. Template.indent(
  363. "promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));"
  364. ),
  365. "} else onFactory(promise);"
  366. ]),
  367. "} catch(e) { onError(e); }",
  368. "}"
  369. ]
  370. )});`
  371. ]),
  372. "}"
  373. ])}`
  374. ])
  375. : "// no chunk loading of consumes"
  376. ]);
  377. }
  378. }
  379. module.exports = ConsumeSharedRuntimeModule;