ExternalModuleInitFragment.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Ivan Kopeykin @vankop
  4. */
  5. "use strict";
  6. const InitFragment = require("../InitFragment");
  7. const makeSerializable = require("../util/makeSerializable");
  8. /** @typedef {import("webpack-sources").Source} Source */
  9. /** @typedef {import("../Generator").GenerateContext} GenerateContext */
  10. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  11. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  12. /** @typedef {{ name: string, value?: string }[]} ArrayImportSpecifiers */
  13. /** @typedef {Set<string>} ImportSpecifier */
  14. /** @typedef {Map<string, ImportSpecifier>} ImportSpecifiers */
  15. /**
  16. * @extends {InitFragment<GenerateContext>}
  17. */
  18. class ExternalModuleInitFragment extends InitFragment {
  19. /**
  20. * @param {string} importedModule imported module
  21. * @param {ArrayImportSpecifiers | ImportSpecifiers} specifiers import specifiers
  22. * @param {string=} defaultImport default import
  23. */
  24. constructor(importedModule, specifiers, defaultImport) {
  25. super(
  26. undefined,
  27. InitFragment.STAGE_CONSTANTS,
  28. 0,
  29. `external module imports|${importedModule}|${defaultImport || "null"}`
  30. );
  31. this.importedModule = importedModule;
  32. if (Array.isArray(specifiers)) {
  33. /** @type {ImportSpecifiers} */
  34. this.specifiers = new Map();
  35. for (const { name, value } of specifiers) {
  36. let specifiers = this.specifiers.get(name);
  37. if (!specifiers) {
  38. /** @type {ImportSpecifier} */
  39. specifiers = new Set();
  40. this.specifiers.set(name, specifiers);
  41. }
  42. specifiers.add(value || name);
  43. }
  44. } else {
  45. this.specifiers = specifiers;
  46. }
  47. this.defaultImport = defaultImport;
  48. }
  49. /**
  50. * @param {ExternalModuleInitFragment} other other
  51. * @returns {ExternalModuleInitFragment} ExternalModuleInitFragment
  52. */
  53. merge(other) {
  54. const newSpecifiersMap = new Map(this.specifiers);
  55. for (const [name, specifiers] of other.specifiers) {
  56. if (newSpecifiersMap.has(name)) {
  57. const currentSpecifiers =
  58. /** @type {Set<string>} */
  59. (newSpecifiersMap.get(name));
  60. for (const spec of specifiers) currentSpecifiers.add(spec);
  61. } else {
  62. newSpecifiersMap.set(name, specifiers);
  63. }
  64. }
  65. return new ExternalModuleInitFragment(
  66. this.importedModule,
  67. newSpecifiersMap,
  68. this.defaultImport
  69. );
  70. }
  71. /**
  72. * Returns the source code that will be included as initialization code.
  73. * @param {GenerateContext} context context
  74. * @returns {string | Source | undefined} the source code that will be included as initialization code
  75. */
  76. getContent({ runtimeRequirements }) {
  77. /** @type {string[]} */
  78. const namedImports = [];
  79. for (const [name, specifiers] of this.specifiers) {
  80. for (const spec of specifiers) {
  81. if (spec === name) {
  82. namedImports.push(name);
  83. } else {
  84. namedImports.push(`${name} as ${spec}`);
  85. }
  86. }
  87. }
  88. let importsString =
  89. namedImports.length > 0 ? `{${namedImports.join(",")}}` : "";
  90. if (this.defaultImport) {
  91. importsString = `${this.defaultImport}${
  92. importsString ? `, ${importsString}` : ""
  93. }`;
  94. }
  95. return `import ${importsString} from ${JSON.stringify(
  96. this.importedModule
  97. )};\n`;
  98. }
  99. /**
  100. * Serializes this instance into the provided serializer context.
  101. * @param {ObjectSerializerContext} context context
  102. */
  103. serialize(context) {
  104. super.serialize(context);
  105. const { write } = context;
  106. write(this.importedModule);
  107. write(this.specifiers);
  108. write(this.defaultImport);
  109. }
  110. /**
  111. * Restores this instance from the provided deserializer context.
  112. * @param {ObjectDeserializerContext} context context
  113. */
  114. deserialize(context) {
  115. super.deserialize(context);
  116. const { read } = context;
  117. this.importedModule = read();
  118. this.specifiers = read();
  119. this.defaultImport = read();
  120. }
  121. }
  122. makeSerializable(
  123. ExternalModuleInitFragment,
  124. "webpack/lib/dependencies/ExternalModuleInitFragment"
  125. );
  126. module.exports = ExternalModuleInitFragment;