CommonJsChunkFormatPlugin.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 { 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 { generateEntryStartup } = require("./StartupHelpers");
  19. /** @typedef {import("../Chunk")} Chunk */
  20. /** @typedef {import("../Compiler")} Compiler */
  21. /** @typedef {import("../Entrypoint")} Entrypoint */
  22. const PLUGIN_NAME = "CommonJsChunkFormatPlugin";
  23. class CommonJsChunkFormatPlugin {
  24. /**
  25. * Apply the plugin
  26. * @param {Compiler} compiler the compiler instance
  27. * @returns {void}
  28. */
  29. apply(compiler) {
  30. compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
  31. compilation.hooks.additionalChunkRuntimeRequirements.tap(
  32. PLUGIN_NAME,
  33. (chunk, set, { chunkGraph }) => {
  34. if (chunk.hasRuntime()) return;
  35. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
  36. set.add(RuntimeGlobals.require);
  37. set.add(RuntimeGlobals.startupEntrypoint);
  38. set.add(RuntimeGlobals.externalInstallChunk);
  39. }
  40. }
  41. );
  42. const hooks = getCompilationHooks(compilation);
  43. hooks.renderChunk.tap(PLUGIN_NAME, (modules, renderContext) => {
  44. const { chunk, chunkGraph, runtimeTemplate } = renderContext;
  45. const source = new ConcatSource();
  46. source.add(`exports.id = ${JSON.stringify(chunk.id)};\n`);
  47. source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`);
  48. source.add("exports.modules = ");
  49. source.add(modules);
  50. source.add(";\n");
  51. const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
  52. if (runtimeModules.length > 0) {
  53. source.add("exports.runtime =\n");
  54. source.add(
  55. Template.renderChunkRuntimeModules(runtimeModules, renderContext)
  56. );
  57. }
  58. const { entries, runtimeChunk } = getChunkInfo(chunk, chunkGraph);
  59. if (runtimeChunk) {
  60. const currentOutputName = compilation
  61. .getPath(
  62. getChunkFilenameTemplate(chunk, compilation.outputOptions),
  63. {
  64. chunk,
  65. contentHashType: "javascript"
  66. }
  67. )
  68. .replace(/^\/+/g, "")
  69. .split("/");
  70. const runtimeOutputName = compilation
  71. .getPath(
  72. getChunkFilenameTemplate(
  73. /** @type {Chunk} */
  74. (runtimeChunk),
  75. compilation.outputOptions
  76. ),
  77. {
  78. chunk: /** @type {Chunk} */ (runtimeChunk),
  79. contentHashType: "javascript"
  80. }
  81. )
  82. .replace(/^\/+/g, "")
  83. .split("/");
  84. // remove common parts
  85. while (
  86. currentOutputName.length > 1 &&
  87. runtimeOutputName.length > 1 &&
  88. currentOutputName[0] === runtimeOutputName[0]
  89. ) {
  90. currentOutputName.shift();
  91. runtimeOutputName.shift();
  92. }
  93. const last = runtimeOutputName.join("/");
  94. // create final path
  95. const runtimePath =
  96. getUndoPath(currentOutputName.join("/"), last, true) + last;
  97. const entrySource = new ConcatSource();
  98. entrySource.add(
  99. `(${
  100. runtimeTemplate.supportsArrowFunction() ? "() => " : "function() "
  101. }{\n`
  102. );
  103. entrySource.add("var exports = {};\n");
  104. entrySource.add(source);
  105. entrySource.add(";\n\n// load runtime\n");
  106. entrySource.add(
  107. `var ${RuntimeGlobals.require} = require(${JSON.stringify(
  108. runtimePath
  109. )});\n`
  110. );
  111. entrySource.add(`${RuntimeGlobals.externalInstallChunk}(exports);\n`);
  112. const startupSource = new RawSource(
  113. generateEntryStartup(
  114. chunkGraph,
  115. runtimeTemplate,
  116. entries,
  117. chunk,
  118. false
  119. )
  120. );
  121. entrySource.add(
  122. hooks.renderStartup.call(
  123. startupSource,
  124. entries[entries.length - 1][0],
  125. {
  126. ...renderContext,
  127. inlined: false
  128. }
  129. )
  130. );
  131. entrySource.add("\n})()");
  132. return entrySource;
  133. }
  134. return source;
  135. });
  136. hooks.chunkHash.tap(PLUGIN_NAME, createChunkHashHandler(PLUGIN_NAME));
  137. });
  138. }
  139. }
  140. module.exports = CommonJsChunkFormatPlugin;