ExternalModuleInitFragment.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. /** @import { Source } from "webpack-sources" */
  9. /** @import { GenerateContext } from "../Generator" */
  10. /** @typedef {{ name: string, value?: string }[]} ArrayImportSpecifiers */
  11. /** @typedef {Set<string>} ImportSpecifier */
  12. /** @typedef {Map<string, ImportSpecifier>} ImportSpecifiers */
  13. /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext<(string | ArrayImportSpecifiers | ImportSpecifiers | undefined)[]>} ObjectDeserializerContext */
  14. /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext<(string | ArrayImportSpecifiers | ImportSpecifiers | undefined)[]>} ObjectSerializerContext */
  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. /** @type {string} */
  32. this.importedModule = importedModule;
  33. if (Array.isArray(specifiers)) {
  34. /** @type {ImportSpecifiers} */
  35. this.specifiers = new Map();
  36. for (const { name, value } of specifiers) {
  37. let specifiers = this.specifiers.get(name);
  38. if (!specifiers) {
  39. /** @type {ImportSpecifier} */
  40. specifiers = new Set();
  41. this.specifiers.set(name, specifiers);
  42. }
  43. specifiers.add(value || name);
  44. }
  45. } else {
  46. this.specifiers = specifiers;
  47. }
  48. /** @type {string | undefined} */
  49. this.defaultImport = defaultImport;
  50. }
  51. /**
  52. * @param {ExternalModuleInitFragment} other other
  53. * @returns {ExternalModuleInitFragment} ExternalModuleInitFragment
  54. */
  55. merge(other) {
  56. const newSpecifiersMap = new Map(this.specifiers);
  57. for (const [name, specifiers] of other.specifiers) {
  58. if (newSpecifiersMap.has(name)) {
  59. const currentSpecifiers =
  60. /** @type {Set<string>} */
  61. (newSpecifiersMap.get(name));
  62. for (const spec of specifiers) currentSpecifiers.add(spec);
  63. } else {
  64. newSpecifiersMap.set(name, specifiers);
  65. }
  66. }
  67. return new ExternalModuleInitFragment(
  68. this.importedModule,
  69. newSpecifiersMap,
  70. this.defaultImport
  71. );
  72. }
  73. /**
  74. * Returns the source code that will be included as initialization code.
  75. * @param {GenerateContext} context context
  76. * @returns {string | Source | undefined} the source code that will be included as initialization code
  77. */
  78. getContent({ runtimeRequirements }) {
  79. /** @type {string[]} */
  80. const namedImports = [];
  81. for (const [name, specifiers] of this.specifiers) {
  82. for (const spec of specifiers) {
  83. if (spec === name) {
  84. namedImports.push(name);
  85. } else {
  86. namedImports.push(`${name} as ${spec}`);
  87. }
  88. }
  89. }
  90. let importsString =
  91. namedImports.length > 0 ? `{${namedImports.join(",")}}` : "";
  92. if (this.defaultImport) {
  93. importsString = `${this.defaultImport}${
  94. importsString ? `, ${importsString}` : ""
  95. }`;
  96. }
  97. return `import ${importsString} from ${JSON.stringify(
  98. this.importedModule
  99. )};\n`;
  100. }
  101. /**
  102. * Serializes this instance into the provided serializer context.
  103. * @param {ObjectSerializerContext} context context
  104. */
  105. serialize(context) {
  106. super.serialize(context);
  107. const { write } = context;
  108. write(this.importedModule);
  109. write(this.specifiers);
  110. write(this.defaultImport);
  111. }
  112. /**
  113. * Restores this instance from the provided deserializer context.
  114. * @param {ObjectDeserializerContext} context context
  115. */
  116. deserialize(context) {
  117. super.deserialize(context);
  118. const { read } = context;
  119. this.importedModule = /** @type {string} */ (read());
  120. this.specifiers = /** @type {ImportSpecifiers} */ (read());
  121. this.defaultImport = /** @type {string | undefined} */ (read());
  122. }
  123. }
  124. makeSerializable(
  125. ExternalModuleInitFragment,
  126. "webpack/lib/dependencies/ExternalModuleInitFragment"
  127. );
  128. module.exports = ExternalModuleInitFragment;