ModuleFederationPlugin.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. const PLUGIN_NAME = "ModuleFederationPlugin";
  35. class ModuleFederationPlugin {
  36. /**
  37. * @param {ModuleFederationPluginOptions} options options
  38. */
  39. constructor(options) {
  40. validate(options);
  41. this._options = options;
  42. }
  43. /**
  44. * Get the compilation hooks associated with this plugin.
  45. * @param {Compilation} compilation The compilation instance.
  46. * @returns {CompilationHooks} The hooks for the compilation.
  47. */
  48. static getCompilationHooks(compilation) {
  49. if (!(compilation instanceof Compilation)) {
  50. throw new TypeError(
  51. "The 'compilation' argument must be an instance of Compilation"
  52. );
  53. }
  54. let hooks = compilationHooksMap.get(compilation);
  55. if (!hooks) {
  56. hooks = {
  57. addContainerEntryDependency: new SyncHook(["dependency"]),
  58. addFederationRuntimeDependency: new SyncHook(["dependency"])
  59. };
  60. compilationHooksMap.set(compilation, hooks);
  61. }
  62. return hooks;
  63. }
  64. /**
  65. * Apply the plugin
  66. * @param {Compiler} compiler the compiler instance
  67. * @returns {void}
  68. */
  69. apply(compiler) {
  70. const { _options: options } = this;
  71. const library = options.library || { type: "var", name: options.name };
  72. const remoteType =
  73. options.remoteType ||
  74. (options.library && isValidExternalsType(options.library.type)
  75. ? /** @type {ExternalsType} */ (options.library.type)
  76. : "script");
  77. if (
  78. library &&
  79. !compiler.options.output.enabledLibraryTypes.includes(library.type)
  80. ) {
  81. compiler.options.output.enabledLibraryTypes.push(library.type);
  82. }
  83. compiler.hooks.afterPlugins.tap(PLUGIN_NAME, () => {
  84. if (
  85. options.exposes &&
  86. (Array.isArray(options.exposes)
  87. ? options.exposes.length > 0
  88. : Object.keys(options.exposes).length > 0)
  89. ) {
  90. new ContainerPlugin({
  91. name: /** @type {string} */ (options.name),
  92. library,
  93. filename: options.filename,
  94. runtime: options.runtime,
  95. shareScope: options.shareScope,
  96. exposes: options.exposes
  97. }).apply(compiler);
  98. }
  99. if (
  100. options.remotes &&
  101. (Array.isArray(options.remotes)
  102. ? options.remotes.length > 0
  103. : Object.keys(options.remotes).length > 0)
  104. ) {
  105. new ContainerReferencePlugin({
  106. remoteType,
  107. shareScope: options.shareScope,
  108. remotes: options.remotes
  109. }).apply(compiler);
  110. }
  111. if (options.shared) {
  112. new SharePlugin({
  113. shared: options.shared,
  114. shareScope: options.shareScope
  115. }).apply(compiler);
  116. }
  117. new HoistContainerReferences().apply(compiler);
  118. });
  119. }
  120. }
  121. module.exports = ModuleFederationPlugin;