CommonJsChunkFormatPlugin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource, RawSource } = require("webpack-sources");
  7. const RuntimeGlobals = require("../RuntimeGlobals");
  8. const Template = require("../Template");
  9. const { getUndoPath } = require("../util/identifier");
  10. const {
  11. createChunkHashHandler,
  12. getChunkInfo
  13. } = require("./ChunkFormatHelpers");
  14. const {
  15. getChunkFilenameTemplate,
  16. getCompilationHooks
  17. } = require("./JavascriptModulesPlugin");
  18. const {
  19. entryStartupAwaitsChunks,
  20. generateEntryStartup
  21. } = require("./StartupHelpers");
  22. /** @import Chunk from "../Chunk" */
  23. /** @import Compiler from "../Compiler" */
  24. const PLUGIN_NAME = "CommonJsChunkFormatPlugin";
  25. class CommonJsChunkFormatPlugin {
  26. /**
  27. * Applies the plugin by registering its hooks on the compiler.
  28. * @param {Compiler} compiler the compiler instance
  29. * @returns {void}
  30. */
  31. apply(compiler) {
  32. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
  33. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  34. PLUGIN_NAME,
  35. (chunk, set, { chunkGraph }) => {
  36. if (chunk.hasRuntime()) return;
  37. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  38. set.add(RuntimeGlobals.require);
  39. // An entry with nothing to wait for is called straight, so the
  40. // helper that waits would have no call site.
  41. if (entryStartupAwaitsChunks(chunkGraph, chunk)) {
  42. set.add(RuntimeGlobals.startupEntrypoint);
  43. }
  44. set.add(RuntimeGlobals.externalInstallChunk);
  45. }
  46. }
  47. );
  48. const hooks = getCompilationHooks(compilation);
  49. hooks.renderChunk.tap(PLUGIN_NAME, (modules, renderContext) => {
  50. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  51. const source = new ConcatSource();
  52. source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`);
  53. source.add("exports.modules = ");
  54. source.add(modules);
  55. source.add(";\n");
  56. const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  57. if (runtimeModules.length > 0) {
  58. source.add("exports.runtime =\n");
  59. source.add(
  60. Template.renderChunkRuntimeModules(runtimeModules, renderContext)
  61. );
  62. }
  63. const { entries, runtimeChunk } = getChunkInfo(chunk, chunkGraph);
  64. if (runtimeChunk) {
  65. const currentOutputName = compilation
  66. .getPath(
  67. getChunkFilenameTemplate(chunk, compilation.outputOptions),
  68. {
  69. chunk,
  70. contentHashType: "javascript"
  71. }
  72. )
  73. .replace(/^\/+/g, "")
  74. .split("/");
  75. const runtimeOutputName = compilation
  76. .getPath(
  77. getChunkFilenameTemplate(
  78. /** @type {Chunk} */
  79. (runtimeChunk),
  80. compilation.outputOptions
  81. ),
  82. {
  83. chunk: /** @type {Chunk} */ (runtimeChunk),
  84. contentHashType: "javascript"
  85. }
  86. )
  87. .replace(/^\/+/g, "")
  88. .split("/");
  89. // remove common parts
  90. while (
  91. currentOutputName.length > 1 &&
  92. runtimeOutputName.length > 1 &&
  93. currentOutputName[0] === runtimeOutputName[0]
  94. ) {
  95. currentOutputName.shift();
  96. runtimeOutputName.shift();
  97. }
  98. const last = runtimeOutputName.join("/");
  99. // create final path
  100. const runtimePath =
  101. getUndoPath(currentOutputName.join("/"), last, true) + last;
  102. const entrySource = new ConcatSource();
  103. entrySource.add(
  104. `(${
  105. runtimeTemplate.supportsArrowFunction() ? "() => " : "function() "
  106. }{\n`
  107. );
  108. entrySource.add("var exports = {};\n");
  109. entrySource.add(source);
  110. entrySource.add(";\n\n// load runtime\n");
  111. entrySource.add(
  112. `var ${RuntimeGlobals.require} = require(${JSON.stringify(
  113. runtimePath
  114. )});\n`
  115. );
  116. entrySource.add(`${RuntimeGlobals.externalInstallChunk}(exports);\n`);
  117. const startupSource = new RawSource(
  118. generateEntryStartup(
  119. chunkGraph,
  120. runtimeTemplate,
  121. entries,
  122. chunk,
  123. false
  124. )
  125. );
  126. entrySource.add(
  127. hooks.renderStartup.call(
  128. startupSource,
  129. entries[entries.length - 1][0],
  130. renderContext
  131. )
  132. );
  133. entrySource.add("\n})()");
  134. return entrySource;
  135. }
  136. return source;
  137. });
  138. hooks.chunkHash.tap(PLUGIN_NAME, createChunkHashHandler(PLUGIN_NAME));
  139. });
  140. }
  141. }
  142. module.exports = CommonJsChunkFormatPlugin;