AmdLibraryPlugin.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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(m => m instanceof ExternalModule);
  83. const externals = /** @type {ExternalModule[]} */ (modules);
  84. const externalsDepsArray = JSON.stringify(
  85. externals.map(m =>
  86. typeof m.request === "object" && !Array.isArray(m.request)
  87. ? m.request.amd
  88. : m.request
  89. )
  90. );
  91. const externalsArguments = externals
  92. .map(
  93. m =>
  94. `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
  95. `${chunkGraph.getModuleId(m)}`
  96. )}__`
  97. )
  98. .join(", ");
  99. const iife = runtimeTemplate.isIIFE();
  100. const fnStart =
  101. (modern
  102. ? `(${externalsArguments}) => {`
  103. : `function(${externalsArguments}) {`) +
  104. (iife || !chunk.hasRuntime() ? " return " : "\n");
  105. const fnEnd = iife ? ";\n}" : "\n}";
  106. let amdContainerPrefix = "";
  107. if (options.amdContainer) {
  108. amdContainerPrefix = `${options.amdContainer}.`;
  109. }
  110. if (this.requireAsWrapper) {
  111. return new ConcatSource(
  112. `${amdContainerPrefix}require(${externalsDepsArray}, ${fnStart}`,
  113. source,
  114. `${fnEnd});`
  115. );
  116. } else if (options.name) {
  117. const name = compilation.getPath(options.name, {
  118. chunk
  119. });
  120. return new ConcatSource(
  121. `${amdContainerPrefix}define(${JSON.stringify(
  122. name
  123. )}, ${externalsDepsArray}, ${fnStart}`,
  124. source,
  125. `${fnEnd});`
  126. );
  127. } else if (externalsArguments) {
  128. return new ConcatSource(
  129. `${amdContainerPrefix}define(${externalsDepsArray}, ${fnStart}`,
  130. source,
  131. `${fnEnd});`
  132. );
  133. } else {
  134. return new ConcatSource(
  135. `${amdContainerPrefix}define(${fnStart}`,
  136. source,
  137. `${fnEnd});`
  138. );
  139. }
  140. }
  141. /**
  142. * @param {Chunk} chunk the chunk
  143. * @param {Hash} hash hash
  144. * @param {ChunkHashContext} chunkHashContext chunk hash context
  145. * @param {LibraryContext<T>} libraryContext context
  146. * @returns {void}
  147. */
  148. chunkHash(chunk, hash, chunkHashContext, { options, compilation }) {
  149. hash.update("AmdLibraryPlugin");
  150. if (this.requireAsWrapper) {
  151. hash.update("requireAsWrapper");
  152. } else if (options.name) {
  153. hash.update("named");
  154. const name = compilation.getPath(options.name, {
  155. chunk
  156. });
  157. hash.update(name);
  158. } else if (options.amdContainer) {
  159. hash.update("amdContainer");
  160. hash.update(options.amdContainer);
  161. }
  162. }
  163. }
  164. module.exports = AmdLibraryPlugin;