ModuleFederationPlugin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
  4. */
  5. "use strict";
  6. const { SyncHook } = require("tapable");
  7. const isValidExternalsType = require("../../schemas/plugins/container/ExternalsType.check");
  8. const Compilation = require("../Compilation");
  9. const SharePlugin = require("../sharing/SharePlugin");
  10. const ContainerPlugin = require("./ContainerPlugin");
  11. const ContainerReferencePlugin = require("./ContainerReferencePlugin");
  12. const HoistContainerReferences = require("./HoistContainerReferencesPlugin");
  13. /** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ExternalsType} ExternalsType */
  14. /** @typedef {import("../../declarations/plugins/container/ModuleFederationPlugin").ModuleFederationPluginOptions} ModuleFederationPluginOptions */
  15. /** @typedef {import("../Compiler")} Compiler */
  16. /** @typedef {import("../Dependency")} Dependency */
  17. /**
  18. * Defines the compilation hooks type used by this module.
  19. * @typedef {object} CompilationHooks
  20. * @property {SyncHook<Dependency>} addContainerEntryDependency
  21. * @property {SyncHook<Dependency>} addFederationRuntimeDependency
  22. */
  23. /** @type {WeakMap<Compilation, CompilationHooks>} */
  24. const compilationHooksMap = new WeakMap();
  25. const PLUGIN_NAME = "ModuleFederationPlugin";
  26. class ModuleFederationPlugin {
  27. /**
  28. * Creates an instance of ModuleFederationPlugin.
  29. * @param {ModuleFederationPluginOptions} options options
  30. */
  31. constructor(options) {
  32. /** @type {ModuleFederationPluginOptions} */
  33. this.options = options;
  34. }
  35. /**
  36. * Get the compilation hooks associated with this plugin.
  37. * @param {Compilation} compilation The compilation instance.
  38. * @returns {CompilationHooks} The hooks for the compilation.
  39. */
  40. static getCompilationHooks(compilation) {
  41. if (!(compilation instanceof Compilation)) {
  42. throw new TypeError(
  43. "The 'compilation' argument must be an instance of Compilation"
  44. );
  45. }
  46. let hooks = compilationHooksMap.get(compilation);
  47. if (!hooks) {
  48. hooks = {
  49. addContainerEntryDependency: new SyncHook(["dependency"]),
  50. addFederationRuntimeDependency: new SyncHook(["dependency"])
  51. };
  52. compilationHooksMap.set(compilation, hooks);
  53. }
  54. return hooks;
  55. }
  56. /**
  57. * Applies the plugin by registering its hooks on the compiler.
  58. * @param {Compiler} compiler the compiler instance
  59. * @returns {void}
  60. */
  61. apply(compiler) {
  62. compiler.hooks.validate.tap(PLUGIN_NAME, () => {
  63. compiler.validate(
  64. () =>
  65. require("../../schemas/plugins/container/ModuleFederationPlugin.json"),
  66. this.options,
  67. {
  68. name: "Module Federation Plugin",
  69. baseDataPath: "options"
  70. },
  71. (options) =>
  72. require("../../schemas/plugins/container/ModuleFederationPlugin.check")(
  73. options
  74. )
  75. );
  76. });
  77. const { options } = this;
  78. const library = options.library || { type: "var", name: options.name };
  79. const remoteType =
  80. options.remoteType ||
  81. (options.library && isValidExternalsType(options.library.type)
  82. ? /** @type {ExternalsType} */ (options.library.type)
  83. : "script");
  84. if (
  85. library &&
  86. !compiler.options.output.enabledLibraryTypes.includes(library.type)
  87. ) {
  88. compiler.options.output.enabledLibraryTypes.push(library.type);
  89. }
  90. compiler.hooks.afterPlugins.tap(PLUGIN_NAME, () => {
  91. if (
  92. options.exposes &&
  93. (Array.isArray(options.exposes)
  94. ? options.exposes.length > 0
  95. : Object.keys(options.exposes).length > 0)
  96. ) {
  97. new ContainerPlugin({
  98. name: /** @type {string} */ (options.name),
  99. library,
  100. filename: options.filename,
  101. runtime: options.runtime,
  102. shareScope: options.shareScope,
  103. exposes: options.exposes
  104. }).apply(compiler);
  105. }
  106. if (
  107. options.remotes &&
  108. (Array.isArray(options.remotes)
  109. ? options.remotes.length > 0
  110. : Object.keys(options.remotes).length > 0)
  111. ) {
  112. new ContainerReferencePlugin({
  113. remoteType,
  114. shareScope: options.shareScope,
  115. remotes: options.remotes
  116. }).apply(compiler);
  117. }
  118. if (options.shared) {
  119. new SharePlugin({
  120. shared: options.shared,
  121. shareScope: options.shareScope
  122. }).apply(compiler);
  123. }
  124. new HoistContainerReferences().apply(compiler);
  125. });
  126. }
  127. }
  128. module.exports = ModuleFederationPlugin;