ContainerPlugin.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra, Zackary Jackson @ScriptedAlchemy, Marais Rossouw @maraisr
  4. */
  5. "use strict";
  6. const ContainerEntryDependency = require("./ContainerEntryDependency");
  7. const ContainerEntryModuleFactory = require("./ContainerEntryModuleFactory");
  8. const ContainerExposedDependency = require("./ContainerExposedDependency");
  9. const getModuleFederationCompilationHooks = require("./moduleFederationHooks");
  10. const { parseOptions } = require("./options");
  11. /**
  12. * @import {
  13. * ContainerPluginOptions
  14. * } from "../../declarations/plugins/container/ContainerPlugin"
  15. */
  16. /** @import Compiler from "../Compiler" */
  17. /** @import { ExposesList } from "./ContainerEntryModule" */
  18. const PLUGIN_NAME = "ContainerPlugin";
  19. class ContainerPlugin {
  20. /**
  21. * Creates an instance of ContainerPlugin.
  22. * @param {ContainerPluginOptions} options options
  23. */
  24. constructor(options) {
  25. /** @type {ContainerPluginOptions} */
  26. this.options = options;
  27. }
  28. /**
  29. * Applies the plugin by registering its hooks on the compiler.
  30. * @param {Compiler} compiler the compiler instance
  31. * @returns {void}
  32. */
  33. apply(compiler) {
  34. compiler.hooks.validate.tap(PLUGIN_NAME, () => {
  35. compiler.validate(
  36. () => require("../../schemas/plugins/container/ContainerPlugin.json"),
  37. this.options,
  38. {
  39. name: "Container Plugin",
  40. baseDataPath: "options"
  41. },
  42. (options) =>
  43. require("../../schemas/plugins/container/ContainerPlugin.check")(
  44. options
  45. )
  46. );
  47. });
  48. const library = this.options.library || {
  49. type: "var",
  50. name: this.options.name
  51. };
  52. if (!compiler.options.output.enabledLibraryTypes.includes(library.type)) {
  53. compiler.options.output.enabledLibraryTypes.push(library.type);
  54. }
  55. const exposes = /** @type {ExposesList} */ (
  56. parseOptions(
  57. this.options.exposes,
  58. (item) => ({
  59. import: Array.isArray(item) ? item : [item],
  60. name: undefined
  61. }),
  62. (item) => ({
  63. import: Array.isArray(item.import) ? item.import : [item.import],
  64. name: item.name || undefined
  65. })
  66. )
  67. );
  68. const shareScope = this.options.shareScope || "default";
  69. compiler.hooks.make.tapAsync(PLUGIN_NAME, (compilation, callback) => {
  70. const hooks = getModuleFederationCompilationHooks(compilation);
  71. const dep = new ContainerEntryDependency(
  72. this.options.name,
  73. exposes,
  74. shareScope
  75. );
  76. dep.loc = { name: this.options.name };
  77. compilation.addEntry(
  78. compilation.options.context,
  79. dep,
  80. {
  81. name: this.options.name,
  82. filename: this.options.filename,
  83. runtime: this.options.runtime,
  84. library
  85. },
  86. (error) => {
  87. if (error) return callback(error);
  88. hooks.addContainerEntryDependency.call(dep);
  89. callback();
  90. }
  91. );
  92. });
  93. compiler.hooks.thisCompilation.tap(
  94. PLUGIN_NAME,
  95. (compilation, { normalModuleFactory }) => {
  96. compilation.dependencyFactories.set(
  97. ContainerEntryDependency,
  98. new ContainerEntryModuleFactory()
  99. );
  100. compilation.dependencyFactories.set(
  101. ContainerExposedDependency,
  102. normalModuleFactory
  103. );
  104. }
  105. );
  106. }
  107. }
  108. module.exports = ContainerPlugin;