AmdLibraryPlugin.js 5.2 KB

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