DefinePropertyGettersRuntimeModule.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const RuntimeGlobals = require("../RuntimeGlobals");
  6. const Template = require("../Template");
  7. const HelperRuntimeModule = require("./HelperRuntimeModule");
  8. /** @import Compilation from "../Compilation" */
  9. /** @import { ReadOnlyRuntimeRequirements } from "../Module" */
  10. class DefinePropertyGettersRuntimeModule extends HelperRuntimeModule {
  11. /**
  12. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
  13. */
  14. constructor(runtimeRequirements) {
  15. super("define property getters");
  16. /** @type {ReadOnlyRuntimeRequirements} */
  17. this.runtimeRequirements = runtimeRequirements;
  18. }
  19. /**
  20. * Returns true, if the runtime module should get it's own scope.
  21. * When false, `generate()` must emit complete statements ending with `;`
  22. * so a following runtime IIFE is not parsed as a call (ASI).
  23. * @returns {boolean} true, if the runtime module should get it's own scope
  24. */
  25. shouldIsolate() {
  26. return false;
  27. }
  28. /**
  29. * Generates runtime code for this runtime module.
  30. * @returns {string | null} runtime code
  31. */
  32. generate() {
  33. const compilation = /** @type {Compilation} */ (this.compilation);
  34. const { runtimeTemplate } = compilation;
  35. const fn = RuntimeGlobals.definePropertyGetters;
  36. // Only webpack emits the array form, so a build emitting none cannot
  37. // receive one; the object form stays either way (see the note below).
  38. const withArray = this.runtimeRequirements.has(
  39. RuntimeGlobals.definePropertyGettersFromArray
  40. );
  41. // TODO webpack 6: remove object format support. Internal code (e.g. ConcatenatedModule)
  42. // and third-party libraries may still call __webpack_require__.d() with an object.
  43. const fromObject = [
  44. "for(var key in definition) {",
  45. Template.indent([
  46. `if(${RuntimeGlobals.hasOwnProperty}(definition, key) && !${RuntimeGlobals.hasOwnProperty}(exports, key)) {`,
  47. Template.indent([
  48. "Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });"
  49. ]),
  50. "}"
  51. ]),
  52. "}"
  53. ];
  54. return Template.asString([
  55. "// define getter/value functions for harmony exports",
  56. `${fn} = ${runtimeTemplate.basicFunction(
  57. "exports, definition",
  58. withArray
  59. ? [
  60. "if(Array.isArray(definition)) {",
  61. Template.indent([
  62. "var i = 0;",
  63. "while(i < definition.length) {",
  64. Template.indent([
  65. "var key = definition[i++];",
  66. "var binding = definition[i++];",
  67. // The descriptor is built before the own-property check so a
  68. // value binding consumes its slot either way.
  69. "var descriptor = binding === 0 ? { enumerable: true, value: definition[i++] } : { enumerable: true, get: binding };",
  70. `if(!${RuntimeGlobals.hasOwnProperty}(exports, key)) Object.defineProperty(exports, key, descriptor);`
  71. ]),
  72. "}"
  73. ]),
  74. "} else {",
  75. Template.indent(fromObject),
  76. "}"
  77. ]
  78. : fromObject
  79. )};`
  80. ]);
  81. }
  82. }
  83. module.exports = DefinePropertyGettersRuntimeModule;