CommonJsSelfReferenceDependency.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const RuntimeGlobals = require("../RuntimeGlobals");
  7. const { equals } = require("../util/ArrayHelpers");
  8. const makeSerializable = require("../util/makeSerializable");
  9. const { propertyAccess } = require("../util/property");
  10. const NullDependency = require("./NullDependency");
  11. /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
  12. /** @typedef {import("../Dependency")} Dependency */
  13. /** @typedef {import("../Dependency").ReferencedExports} ReferencedExports */
  14. /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
  15. /** @typedef {import("../ModuleGraph")} ModuleGraph */
  16. /** @typedef {import("../ExportsInfo").ExportInfoName} ExportInfoName */
  17. /** @typedef {import("../javascript/JavascriptParser").Range} Range */
  18. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  19. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  20. /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
  21. /** @typedef {import("./CommonJsDependencyHelpers").CommonJSDependencyBaseKeywords} CommonJSDependencyBaseKeywords */
  22. class CommonJsSelfReferenceDependency extends NullDependency {
  23. /**
  24. * Creates an instance of CommonJsSelfReferenceDependency.
  25. * @param {Range} range range
  26. * @param {CommonJSDependencyBaseKeywords} base base
  27. * @param {ExportInfoName[]} names names
  28. * @param {boolean} call is a call
  29. */
  30. constructor(range, base, names, call) {
  31. super();
  32. this.range = range;
  33. this.base = base;
  34. this.names = names;
  35. this.call = call;
  36. }
  37. get type() {
  38. return "cjs self exports reference";
  39. }
  40. get category() {
  41. return "self";
  42. }
  43. /**
  44. * Returns an identifier to merge equal requests.
  45. * @returns {string | null} an identifier to merge equal requests
  46. */
  47. getResourceIdentifier() {
  48. return "self";
  49. }
  50. /**
  51. * Returns list of exports referenced by this dependency
  52. * @param {ModuleGraph} moduleGraph module graph
  53. * @param {RuntimeSpec} runtime the runtime for which the module is analysed
  54. * @returns {ReferencedExports} referenced exports
  55. */
  56. getReferencedExports(moduleGraph, runtime) {
  57. return [this.call ? this.names.slice(0, -1) : this.names];
  58. }
  59. /**
  60. * Serializes this instance into the provided serializer context.
  61. * @param {ObjectSerializerContext} context context
  62. */
  63. serialize(context) {
  64. const { write } = context;
  65. write(this.range);
  66. write(this.base);
  67. write(this.names);
  68. write(this.call);
  69. super.serialize(context);
  70. }
  71. /**
  72. * Restores this instance from the provided deserializer context.
  73. * @param {ObjectDeserializerContext} context context
  74. */
  75. deserialize(context) {
  76. const { read } = context;
  77. this.range = read();
  78. this.base = read();
  79. this.names = read();
  80. this.call = read();
  81. super.deserialize(context);
  82. }
  83. }
  84. makeSerializable(
  85. CommonJsSelfReferenceDependency,
  86. "webpack/lib/dependencies/CommonJsSelfReferenceDependency"
  87. );
  88. CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependencyTemplate extends (
  89. NullDependency.Template
  90. ) {
  91. /**
  92. * Applies the plugin by registering its hooks on the compiler.
  93. * @param {Dependency} dependency the dependency for which the template should be applied
  94. * @param {ReplaceSource} source the current replace source which can be modified
  95. * @param {DependencyTemplateContext} templateContext the context object
  96. * @returns {void}
  97. */
  98. apply(
  99. dependency,
  100. source,
  101. { module, moduleGraph, runtime, runtimeRequirements }
  102. ) {
  103. const dep = /** @type {CommonJsSelfReferenceDependency} */ (dependency);
  104. const used =
  105. dep.names.length === 0
  106. ? dep.names
  107. : moduleGraph.getExportsInfo(module).getUsedName(dep.names, runtime);
  108. if (!used) {
  109. throw new Error(
  110. "Self-reference dependency has unused export name: This should not happen"
  111. );
  112. }
  113. /** @type {string} */
  114. let base;
  115. switch (dep.base) {
  116. case "exports":
  117. runtimeRequirements.add(RuntimeGlobals.exports);
  118. base = module.exportsArgument;
  119. break;
  120. case "module.exports":
  121. runtimeRequirements.add(RuntimeGlobals.module);
  122. base = `${module.moduleArgument}.exports`;
  123. break;
  124. case "this":
  125. runtimeRequirements.add(RuntimeGlobals.thisAsExports);
  126. base = "this";
  127. break;
  128. default:
  129. throw new Error(`Unsupported base ${dep.base}`);
  130. }
  131. if (base === dep.base && equals(used, dep.names)) {
  132. // Nothing has to be changed
  133. // We don't use a replacement for compat reasons
  134. // for plugins that update `module._source` which they
  135. // shouldn't do!
  136. return;
  137. }
  138. source.replace(
  139. dep.range[0],
  140. dep.range[1] - 1,
  141. `${base}${propertyAccess(used)}`
  142. );
  143. }
  144. };
  145. module.exports = CommonJsSelfReferenceDependency;