CommonJsChunkFormatPlugin.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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 {
  10. getChunkFilenameTemplate,
  11. getCompilationHooks
  12. } = require("./JavascriptModulesPlugin");
  13. const {
  14. generateEntryStartup,
  15. updateHashForEntryStartup
  16. } = require("./StartupHelpers");
  17. /** @typedef {import("../Compiler")} Compiler */
  18. class CommonJsChunkFormatPlugin {
  19. /**
  20. * Apply the plugin
  21. * @param {Compiler} compiler the compiler instance
  22. * @returns {void}
  23. */
  24. apply(compiler) {
  25. compiler.hooks.thisCompilation.tap(
  26. "CommonJsChunkFormatPlugin",
  27. compilation => {
  28. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  29. "CommonJsChunkLoadingPlugin",
  30. (chunk, set, { chunkGraph }) => {
  31. if (chunk.hasRuntime()) return;
  32. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  33. set.add(RuntimeGlobals.require);
  34. set.add(RuntimeGlobals.startupEntrypoint);
  35. set.add(RuntimeGlobals.externalInstallChunk);
  36. }
  37. }
  38. );
  39. const hooks = getCompilationHooks(compilation);
  40. hooks.renderChunk.tap(
  41. "CommonJsChunkFormatPlugin",
  42. (modules, renderContext) => {
  43. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  44. const source = new ConcatSource();
  45. source.add(`exports.id = ${JSON.stringify(chunk.id)};\n`);
  46. source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`);
  47. source.add(`exports.modules = `);
  48. source.add(modules);
  49. source.add(";\n");
  50. const runtimeModules =
  51. chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  52. if (runtimeModules.length > 0) {
  53. source.add("exports.runtime =\n");
  54. source.add(
  55. Template.renderChunkRuntimeModules(
  56. runtimeModules,
  57. renderContext
  58. )
  59. );
  60. }
  61. const entries = Array.from(
  62. chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
  63. );
  64. if (entries.length > 0) {
  65. const runtimeChunk = entries[0][1].getRuntimeChunk();
  66. const currentOutputName = compilation
  67. .getPath(
  68. getChunkFilenameTemplate(chunk, compilation.outputOptions),
  69. {
  70. chunk,
  71. contentHashType: "javascript"
  72. }
  73. )
  74. .split("/");
  75. const runtimeOutputName = compilation
  76. .getPath(
  77. getChunkFilenameTemplate(
  78. runtimeChunk,
  79. compilation.outputOptions
  80. ),
  81. {
  82. chunk: runtimeChunk,
  83. contentHashType: "javascript"
  84. }
  85. )
  86. .split("/");
  87. // remove filename, we only need the directory
  88. currentOutputName.pop();
  89. // remove common parts
  90. while (
  91. currentOutputName.length > 0 &&
  92. runtimeOutputName.length > 0 &&
  93. currentOutputName[0] === runtimeOutputName[0]
  94. ) {
  95. currentOutputName.shift();
  96. runtimeOutputName.shift();
  97. }
  98. // create final path
  99. const runtimePath =
  100. (currentOutputName.length > 0
  101. ? "../".repeat(currentOutputName.length)
  102. : "./") + runtimeOutputName.join("/");
  103. const entrySource = new ConcatSource();
  104. entrySource.add(
  105. `(${
  106. runtimeTemplate.supportsArrowFunction()
  107. ? "() => "
  108. : "function() "
  109. }{\n`
  110. );
  111. entrySource.add("var exports = {};\n");
  112. entrySource.add(source);
  113. entrySource.add(";\n\n// load runtime\n");
  114. entrySource.add(
  115. `var __webpack_require__ = require(${JSON.stringify(
  116. runtimePath
  117. )});\n`
  118. );
  119. entrySource.add(
  120. `${RuntimeGlobals.externalInstallChunk}(exports);\n`
  121. );
  122. const startupSource = new RawSource(
  123. generateEntryStartup(
  124. chunkGraph,
  125. runtimeTemplate,
  126. entries,
  127. chunk,
  128. false
  129. )
  130. );
  131. entrySource.add(
  132. hooks.renderStartup.call(
  133. startupSource,
  134. entries[entries.length - 1][0],
  135. {
  136. ...renderContext,
  137. inlined: false
  138. }
  139. )
  140. );
  141. entrySource.add("\n})()");
  142. return entrySource;
  143. }
  144. return source;
  145. }
  146. );
  147. hooks.chunkHash.tap(
  148. "CommonJsChunkFormatPlugin",
  149. (chunk, hash, { chunkGraph }) => {
  150. if (chunk.hasRuntime()) return;
  151. hash.update("CommonJsChunkFormatPlugin");
  152. hash.update("1");
  153. const entries = Array.from(
  154. chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
  155. );
  156. updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
  157. }
  158. );
  159. }
  160. );
  161. }
  162. }
  163. module.exports = CommonJsChunkFormatPlugin;