AmdLibraryPlugin.js 4.9 KB

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