AmdLibraryPlugin.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource } = require("webpack-sources");
  7. const ExternalModule = require("../ExternalModule");
  8. const Template = require("../Template");
  9. const AbstractLibraryPlugin = require("./AbstractLibraryPlugin");
  10. /** @typedef {import("webpack-sources").Source} Source */
  11. /** @typedef {import("../../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
  12. /** @typedef {import("../../declarations/WebpackOptions").LibraryType} LibraryType */
  13. /** @typedef {import("../Chunk")} Chunk */
  14. /** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
  15. /** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */
  16. /** @typedef {import("../util/Hash")} Hash */
  17. /**
  18. * Defines the shared type used by this module.
  19. * @template T
  20. * @typedef {import("./AbstractLibraryPlugin").LibraryContext<T>} LibraryContext<T>
  21. */
  22. /**
  23. * Defines the amd library plugin options type used by this module.
  24. * @typedef {object} AmdLibraryPluginOptions
  25. * @property {LibraryType} type
  26. * @property {boolean=} requireAsWrapper
  27. */
  28. /**
  29. * Defines the amd library plugin parsed type used by this module.
  30. * @typedef {object} AmdLibraryPluginParsed
  31. * @property {string} name
  32. * @property {string} amdContainer
  33. */
  34. /**
  35. * Represents the amd library plugin runtime component.
  36. * @typedef {AmdLibraryPluginParsed} T
  37. * @extends {AbstractLibraryPlugin<AmdLibraryPluginParsed>}
  38. */
  39. class AmdLibraryPlugin extends AbstractLibraryPlugin {
  40. /**
  41. * Creates an instance of AmdLibraryPlugin.
  42. * @param {AmdLibraryPluginOptions} options the plugin options
  43. */
  44. constructor(options) {
  45. super({
  46. pluginName: "AmdLibraryPlugin",
  47. type: options.type
  48. });
  49. /** @type {AmdLibraryPluginOptions["requireAsWrapper"]} */
  50. this.requireAsWrapper = options.requireAsWrapper;
  51. }
  52. /**
  53. * Returns preprocess as needed by overriding.
  54. * @param {LibraryOptions} library normalized library option
  55. * @returns {T} preprocess as needed by overriding
  56. */
  57. parseOptions(library) {
  58. const { name, amdContainer } = library;
  59. if (this.requireAsWrapper) {
  60. if (name) {
  61. throw new Error(
  62. `AMD library name must be unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}`
  63. );
  64. }
  65. } else if (name && typeof name !== "string") {
  66. throw new Error(
  67. `AMD library name must be a simple string or unset. ${AbstractLibraryPlugin.COMMON_LIBRARY_NAME_MESSAGE}`
  68. );
  69. }
  70. const _name = /** @type {string} */ (name);
  71. const _amdContainer = /** @type {string} */ (amdContainer);
  72. return { name: _name, amdContainer: _amdContainer };
  73. }
  74. /**
  75. * Returns source with library export.
  76. * @param {Source} source source
  77. * @param {RenderContext} renderContext render context
  78. * @param {LibraryContext<T>} libraryContext context
  79. * @returns {Source} source with library export
  80. */
  81. render(
  82. source,
  83. { chunkGraph, chunk, runtimeTemplate },
  84. { options, compilation }
  85. ) {
  86. const modern = runtimeTemplate.supportsArrowFunction();
  87. const modules = chunkGraph
  88. .getChunkModules(chunk)
  89. .filter(
  90. (m) =>
  91. m instanceof ExternalModule &&
  92. (m.externalType === "amd" || m.externalType === "amd-require")
  93. );
  94. const externals = /** @type {ExternalModule[]} */ (modules);
  95. const externalsDepsArray = JSON.stringify(
  96. externals.map((m) =>
  97. typeof m.request === "object" && !Array.isArray(m.request)
  98. ? m.request.amd
  99. : m.request
  100. )
  101. );
  102. const externalsArguments = externals
  103. .map(
  104. (m) =>
  105. `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
  106. `${chunkGraph.getModuleId(m)}`
  107. )}__`
  108. )
  109. .join(", ");
  110. const iife = runtimeTemplate.isIIFE();
  111. const fnStart =
  112. (modern
  113. ? `(${externalsArguments}) => {`
  114. : `function(${externalsArguments}) {`) +
  115. (iife || !chunk.hasRuntime() ? " return " : "\n");
  116. const fnEnd = iife ? ";\n}" : "\n}";
  117. let amdContainerPrefix = "";
  118. if (options.amdContainer) {
  119. amdContainerPrefix = `${options.amdContainer}.`;
  120. }
  121. if (this.requireAsWrapper) {
  122. return new ConcatSource(
  123. `${amdContainerPrefix}require(${externalsDepsArray}, ${fnStart}`,
  124. source,
  125. `${fnEnd});`
  126. );
  127. } else if (options.name) {
  128. const name = compilation.getPath(options.name, {
  129. chunk
  130. });
  131. return new ConcatSource(
  132. `${amdContainerPrefix}define(${JSON.stringify(
  133. name
  134. )}, ${externalsDepsArray}, ${fnStart}`,
  135. source,
  136. `${fnEnd});`
  137. );
  138. } else if (externalsArguments) {
  139. return new ConcatSource(
  140. `${amdContainerPrefix}define(${externalsDepsArray}, ${fnStart}`,
  141. source,
  142. `${fnEnd});`
  143. );
  144. }
  145. return new ConcatSource(
  146. `${amdContainerPrefix}define(${fnStart}`,
  147. source,
  148. `${fnEnd});`
  149. );
  150. }
  151. /**
  152. * Processes the provided chunk.
  153. * @param {Chunk} chunk the chunk
  154. * @param {Hash} hash hash
  155. * @param {ChunkHashContext} chunkHashContext chunk hash context
  156. * @param {LibraryContext<T>} libraryContext context
  157. * @returns {void}
  158. */
  159. chunkHash(chunk, hash, chunkHashContext, { options, compilation }) {
  160. hash.update("AmdLibraryPlugin");
  161. if (this.requireAsWrapper) {
  162. hash.update("requireAsWrapper");
  163. } else if (options.name) {
  164. hash.update("named");
  165. const name = compilation.getPath(options.name, {
  166. chunk
  167. });
  168. hash.update(name);
  169. } else if (options.amdContainer) {
  170. hash.update("amdContainer");
  171. hash.update(options.amdContainer);
  172. }
  173. }
  174. }
  175. module.exports = AmdLibraryPlugin;