123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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").ConcatSource;
  7. const OriginalSource = require("webpack-sources").OriginalSource;
  8. const Template = require("./Template");
  9. function accessorToObjectAccess(accessor) {
  10. return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
  11. }
  12. function accessorAccess(base, accessor) {
  13. accessor = [].concat(accessor);
  14. return accessor.map((a, idx) => {
  15. a = base + accessorToObjectAccess(accessor.slice(0, idx + 1));
  16. if(idx === accessor.length - 1) return a;
  17. return `${a} = ${a} || {}`;
  18. }).join(", ");
  19. }
  20. class UmdMainTemplatePlugin {
  21. constructor(name, options) {
  22. if(typeof name === "object" && !Array.isArray(name)) {
  23. this.name = name.root || name.amd || name.commonjs;
  24. this.names = name;
  25. } else {
  26. this.name = name;
  27. this.names = {
  28. commonjs: name,
  29. root: name,
  30. amd: name
  31. };
  32. }
  33. this.optionalAmdExternalAsGlobal = options.optionalAmdExternalAsGlobal;
  34. this.namedDefine = options.namedDefine;
  35. this.auxiliaryComment = options.auxiliaryComment;
  36. }
  37. apply(compilation) {
  38. const mainTemplate = compilation.mainTemplate;
  39. compilation.templatesPlugin("render-with-entry", (source, chunk, hash) => {
  40. let externals = chunk.getModules().filter(m => m.external && (m.type === "umd" || m.type === "umd2"));
  41. const optionalExternals = [];
  42. let requiredExternals = [];
  43. if(this.optionalAmdExternalAsGlobal) {
  44. externals.forEach(m => {
  45. if(m.optional) {
  46. optionalExternals.push(m);
  47. } else {
  48. requiredExternals.push(m);
  49. }
  50. });
  51. externals = requiredExternals.concat(optionalExternals);
  52. } else {
  53. requiredExternals = externals;
  54. }
  55. function replaceKeys(str) {
  56. return mainTemplate.applyPluginsWaterfall("asset-path", str, {
  57. hash,
  58. chunk
  59. });
  60. }
  61. function externalsDepsArray(modules) {
  62. return `[${replaceKeys(modules.map(m => JSON.stringify(typeof m.request === "object" ? m.request.amd : m.request)).join(", "))}]`;
  63. }
  64. function externalsRootArray(modules) {
  65. return replaceKeys(modules.map(m => {
  66. let request = m.request;
  67. if(typeof request === "object") request = request.root;
  68. return `root${accessorToObjectAccess([].concat(request))}`;
  69. }).join(", "));
  70. }
  71. function externalsRequireArray(type) {
  72. return replaceKeys(externals.map(m => {
  73. let expr;
  74. let request = m.request;
  75. if(typeof request === "object") request = request[type];
  76. if(typeof request === "undefined") throw new Error("Missing external configuration for type:" + type);
  77. if(Array.isArray(request)) {
  78. expr = `require(${JSON.stringify(request[0])})${accessorToObjectAccess(request.slice(1))}`;
  79. } else
  80. expr = `require(${JSON.stringify(request)})`;
  81. if(m.optional) {
  82. expr = `(function webpackLoadOptionalExternalModule() { try { return ${expr}; } catch(e) {} }())`;
  83. }
  84. return expr;
  85. }).join(", "));
  86. }
  87. function externalsArguments(modules) {
  88. return modules.map(m => Template.toIdentifier(`__WEBPACK_EXTERNAL_MODULE_${m.id}__`)).join(", ");
  89. }
  90. function libraryName(library) {
  91. return JSON.stringify(replaceKeys([].concat(library).pop()));
  92. }
  93. let amdFactory;
  94. if(optionalExternals.length > 0) {
  95. const wrapperArguments = externalsArguments(requiredExternals);
  96. const factoryArguments = requiredExternals.length > 0 ?
  97. externalsArguments(requiredExternals) + ", " + externalsRootArray(optionalExternals) :
  98. externalsRootArray(optionalExternals);
  99. amdFactory = `function webpackLoadOptionalExternalModuleAmd(${wrapperArguments}) {\n` +
  100. ` return factory(${factoryArguments});\n` +
  101. " }";
  102. } else {
  103. amdFactory = "factory";
  104. }
  105. return new ConcatSource(new OriginalSource(
  106. "(function webpackUniversalModuleDefinition(root, factory) {\n" +
  107. (this.auxiliaryComment &&
  108. typeof this.auxiliaryComment === "string" ?
  109. " //" + this.auxiliaryComment + "\n" :
  110. this.auxiliaryComment.commonjs2 ?
  111. " //" + this.auxiliaryComment.commonjs2 + "\n" :
  112. ""
  113. ) +
  114. " if(typeof exports === 'object' && typeof module === 'object')\n" +
  115. " module.exports = factory(" + externalsRequireArray("commonjs2") + ");\n" +
  116. (this.auxiliaryComment &&
  117. typeof this.auxiliaryComment === "string" ?
  118. " //" + this.auxiliaryComment + "\n" :
  119. this.auxiliaryComment.amd ?
  120. " //" + this.auxiliaryComment.amd + "\n" :
  121. ""
  122. ) +
  123. " else if(typeof define === 'function' && define.amd)\n" +
  124. (requiredExternals.length > 0 ?
  125. (this.names.amd && this.namedDefine === true ?
  126. " define(" + libraryName(this.names.amd) + ", " + externalsDepsArray(requiredExternals) + ", " + amdFactory + ");\n" :
  127. " define(" + externalsDepsArray(requiredExternals) + ", " + amdFactory + ");\n"
  128. ) :
  129. (this.names.amd && this.namedDefine === true ?
  130. " define(" + libraryName(this.names.amd) + ", [], " + amdFactory + ");\n" :
  131. " define([], " + amdFactory + ");\n"
  132. )
  133. ) +
  134. (this.names.root || this.names.commonjs ?
  135. (this.auxiliaryComment &&
  136. typeof this.auxiliaryComment === "string" ?
  137. " //" + this.auxiliaryComment + "\n" :
  138. this.auxiliaryComment.commonjs ?
  139. " //" + this.auxiliaryComment.commonjs + "\n" :
  140. ""
  141. ) +
  142. " else if(typeof exports === 'object')\n" +
  143. " exports[" + libraryName(this.names.commonjs || this.names.root) + "] = factory(" + externalsRequireArray("commonjs") + ");\n" +
  144. (this.auxiliaryComment &&
  145. typeof this.auxiliaryComment === "string" ?
  146. " //" + this.auxiliaryComment + "\n" :
  147. this.auxiliaryComment.root ?
  148. " //" + this.auxiliaryComment.root + "\n" :
  149. ""
  150. ) +
  151. " else\n" +
  152. " " + replaceKeys(accessorAccess("root", this.names.root || this.names.commonjs)) + " = factory(" + externalsRootArray(externals) + ");\n" :
  153. " else {\n" +
  154. (externals.length > 0 ?
  155. " var a = typeof exports === 'object' ? factory(" + externalsRequireArray("commonjs") + ") : factory(" + externalsRootArray(externals) + ");\n" :
  156. " var a = factory();\n"
  157. ) +
  158. " for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" +
  159. " }\n"
  160. ) +
  161. "})(this, function(" + externalsArguments(externals) + ") {\nreturn ", "webpack/universalModuleDefinition"), source, ";\n})");
  162. });
  163. mainTemplate.plugin("global-hash-paths", (paths) => {
  164. if(this.names.root) paths = paths.concat(this.names.root);
  165. if(this.names.amd) paths = paths.concat(this.names.amd);
  166. if(this.names.commonjs) paths = paths.concat(this.names.commonjs);
  167. return paths;
  168. });
  169. mainTemplate.plugin("hash", (hash) => {
  170. hash.update("umd");
  171. hash.update(`${this.names.root}`);
  172. hash.update(`${this.names.amd}`);
  173. hash.update(`${this.names.commonjs}`);
  174. });
  175. }
  176. }
  177. module.exports = UmdMainTemplatePlugin;