StartupHelpers.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 Template = require("../Template");
  8. const { isSubset } = require("../util/SetHelpers");
  9. const { getAllChunks } = require("./ChunkHelpers");
  10. /** @typedef {import("../util/Hash")} Hash */
  11. /** @typedef {import("../Chunk")} Chunk */
  12. /** @typedef {import("../Chunk").ChunkId} ChunkId */
  13. /** @typedef {import("../Compilation")} Compilation */
  14. /** @typedef {import("../ChunkGraph")} ChunkGraph */
  15. /** @typedef {import("../Entrypoint")} Entrypoint */
  16. /** @typedef {import("../ChunkGraph").EntryModuleWithChunkGroup} EntryModuleWithChunkGroup */
  17. /** @typedef {import("../ChunkGroup")} ChunkGroup */
  18. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  19. /** @typedef {(string|number)[]} EntryItem */
  20. const EXPORT_PREFIX = `var ${RuntimeGlobals.exports} = `;
  21. /**
  22. * @param {ChunkGraph} chunkGraph chunkGraph
  23. * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
  24. * @param {EntryModuleWithChunkGroup[]} entries entries
  25. * @param {Chunk} chunk chunk
  26. * @param {boolean} passive true: passive startup with on chunks loaded
  27. * @returns {string} runtime code
  28. */
  29. exports.generateEntryStartup = (
  30. chunkGraph,
  31. runtimeTemplate,
  32. entries,
  33. chunk,
  34. passive
  35. ) => {
  36. /** @type {string[]} */
  37. const runtime = [
  38. `var __webpack_exec__ = ${runtimeTemplate.returningFunction(
  39. `${RuntimeGlobals.require}(${RuntimeGlobals.entryModuleId} = moduleId)`,
  40. "moduleId"
  41. )}`
  42. ];
  43. const runModule = id => {
  44. return `__webpack_exec__(${JSON.stringify(id)})`;
  45. };
  46. const outputCombination = (chunks, moduleIds, final) => {
  47. if (chunks.size === 0) {
  48. runtime.push(
  49. `${final ? EXPORT_PREFIX : ""}(${moduleIds.map(runModule).join(", ")});`
  50. );
  51. } else {
  52. const fn = runtimeTemplate.returningFunction(
  53. moduleIds.map(runModule).join(", ")
  54. );
  55. runtime.push(
  56. `${final && !passive ? EXPORT_PREFIX : ""}${
  57. passive
  58. ? RuntimeGlobals.onChunksLoaded
  59. : RuntimeGlobals.startupEntrypoint
  60. }(0, ${JSON.stringify(Array.from(chunks, c => c.id))}, ${fn});`
  61. );
  62. if (final && passive) {
  63. runtime.push(`${EXPORT_PREFIX}${RuntimeGlobals.onChunksLoaded}();`);
  64. }
  65. }
  66. };
  67. let currentChunks = undefined;
  68. let currentModuleIds = undefined;
  69. for (const [module, entrypoint] of entries) {
  70. const runtimeChunk =
  71. /** @type {Entrypoint} */
  72. (entrypoint).getRuntimeChunk();
  73. const moduleId = chunkGraph.getModuleId(module);
  74. const chunks = getAllChunks(
  75. /** @type {Entrypoint} */ (entrypoint),
  76. chunk,
  77. runtimeChunk
  78. );
  79. if (
  80. currentChunks &&
  81. currentChunks.size === chunks.size &&
  82. isSubset(currentChunks, chunks)
  83. ) {
  84. currentModuleIds.push(moduleId);
  85. } else {
  86. if (currentChunks) {
  87. outputCombination(currentChunks, currentModuleIds);
  88. }
  89. currentChunks = chunks;
  90. currentModuleIds = [moduleId];
  91. }
  92. }
  93. // output current modules with export prefix
  94. if (currentChunks) {
  95. outputCombination(currentChunks, currentModuleIds, true);
  96. }
  97. runtime.push("");
  98. return Template.asString(runtime);
  99. };
  100. /**
  101. * @param {Hash} hash the hash to update
  102. * @param {ChunkGraph} chunkGraph chunkGraph
  103. * @param {EntryModuleWithChunkGroup[]} entries entries
  104. * @param {Chunk} chunk chunk
  105. * @returns {void}
  106. */
  107. exports.updateHashForEntryStartup = (hash, chunkGraph, entries, chunk) => {
  108. for (const [module, entrypoint] of entries) {
  109. const runtimeChunk =
  110. /** @type {Entrypoint} */
  111. (entrypoint).getRuntimeChunk();
  112. const moduleId = chunkGraph.getModuleId(module);
  113. hash.update(`${moduleId}`);
  114. for (const c of getAllChunks(
  115. /** @type {Entrypoint} */ (entrypoint),
  116. chunk,
  117. /** @type {Chunk} */ (runtimeChunk)
  118. )) {
  119. hash.update(`${c.id}`);
  120. }
  121. }
  122. };
  123. /**
  124. * @param {Chunk} chunk the chunk
  125. * @param {ChunkGraph} chunkGraph the chunk graph
  126. * @param {function(Chunk, ChunkGraph): boolean} filterFn filter function
  127. * @returns {Set<number | string>} initially fulfilled chunk ids
  128. */
  129. exports.getInitialChunkIds = (chunk, chunkGraph, filterFn) => {
  130. const initialChunkIds = new Set(chunk.ids);
  131. for (const c of chunk.getAllInitialChunks()) {
  132. if (c === chunk || filterFn(c, chunkGraph)) continue;
  133. for (const id of /** @type {ChunkId[]} */ (c.ids)) {
  134. initialChunkIds.add(id);
  135. }
  136. }
  137. return initialChunkIds;
  138. };