AmdLibraryPlugin.js 4.9 KB

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