ModuleFederationPlugin.js 4.1 KB

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