ContainerReferencePlugin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 ExternalsPlugin = require("../ExternalsPlugin");
  7. const RuntimeGlobals = require("../RuntimeGlobals");
  8. const createSchemaValidation = require("../util/create-schema-validation");
  9. const FallbackDependency = require("./FallbackDependency");
  10. const FallbackItemDependency = require("./FallbackItemDependency");
  11. const FallbackModuleFactory = require("./FallbackModuleFactory");
  12. const RemoteModule = require("./RemoteModule");
  13. const RemoteRuntimeModule = require("./RemoteRuntimeModule");
  14. const RemoteToExternalDependency = require("./RemoteToExternalDependency");
  15. const { parseOptions } = require("./options");
  16. /** @typedef {import("../../declarations/plugins/container/ContainerReferencePlugin").ContainerReferencePluginOptions} ContainerReferencePluginOptions */
  17. /** @typedef {import("../../declarations/plugins/container/ContainerReferencePlugin").RemotesConfig} RemotesConfig */
  18. /** @typedef {import("../Compiler")} Compiler */
  19. const validate = createSchemaValidation(
  20. require("../../schemas/plugins/container/ContainerReferencePlugin.check.js"),
  21. () =>
  22. require("../../schemas/plugins/container/ContainerReferencePlugin.json"),
  23. {
  24. name: "Container Reference Plugin",
  25. baseDataPath: "options"
  26. }
  27. );
  28. const slashCode = "/".charCodeAt(0);
  29. const PLUGIN_NAME = "ContainerReferencePlugin";
  30. class ContainerReferencePlugin {
  31. /**
  32. * @param {ContainerReferencePluginOptions} options options
  33. */
  34. constructor(options) {
  35. validate(options);
  36. this._remoteType = options.remoteType;
  37. this._remotes = parseOptions(
  38. options.remotes,
  39. item => ({
  40. external: Array.isArray(item) ? item : [item],
  41. shareScope: options.shareScope || "default"
  42. }),
  43. item => ({
  44. external: Array.isArray(item.external)
  45. ? item.external
  46. : [item.external],
  47. shareScope: item.shareScope || options.shareScope || "default"
  48. })
  49. );
  50. }
  51. /**
  52. * Apply the plugin
  53. * @param {Compiler} compiler the compiler instance
  54. * @returns {void}
  55. */
  56. apply(compiler) {
  57. const { _remotes: remotes, _remoteType: remoteType } = this;
  58. /** @type {Record<string, string>} */
  59. const remoteExternals = {};
  60. for (const [key, config] of remotes) {
  61. let i = 0;
  62. for (const external of config.external) {
  63. if (external.startsWith("internal ")) continue;
  64. remoteExternals[
  65. `webpack/container/reference/${key}${i ? `/fallback-${i}` : ""}`
  66. ] = external;
  67. i++;
  68. }
  69. }
  70. new ExternalsPlugin(remoteType, remoteExternals).apply(compiler);
  71. compiler.hooks.compilation.tap(
  72. PLUGIN_NAME,
  73. (compilation, { normalModuleFactory }) => {
  74. compilation.dependencyFactories.set(
  75. RemoteToExternalDependency,
  76. normalModuleFactory
  77. );
  78. compilation.dependencyFactories.set(
  79. FallbackItemDependency,
  80. normalModuleFactory
  81. );
  82. compilation.dependencyFactories.set(
  83. FallbackDependency,
  84. new FallbackModuleFactory()
  85. );
  86. normalModuleFactory.hooks.factorize.tap(PLUGIN_NAME, data => {
  87. if (!data.request.includes("!")) {
  88. for (const [key, config] of remotes) {
  89. if (
  90. data.request.startsWith(`${key}`) &&
  91. (data.request.length === key.length ||
  92. data.request.charCodeAt(key.length) === slashCode)
  93. ) {
  94. return new RemoteModule(
  95. data.request,
  96. config.external.map((external, i) =>
  97. external.startsWith("internal ")
  98. ? external.slice(9)
  99. : `webpack/container/reference/${key}${
  100. i ? `/fallback-${i}` : ""
  101. }`
  102. ),
  103. `.${data.request.slice(key.length)}`,
  104. config.shareScope
  105. );
  106. }
  107. }
  108. }
  109. });
  110. compilation.hooks.runtimeRequirementInTree
  111. .for(RuntimeGlobals.ensureChunkHandlers)
  112. .tap(PLUGIN_NAME, (chunk, set) => {
  113. set.add(RuntimeGlobals.module);
  114. set.add(RuntimeGlobals.moduleFactoriesAddOnly);
  115. set.add(RuntimeGlobals.hasOwnProperty);
  116. set.add(RuntimeGlobals.initializeSharing);
  117. set.add(RuntimeGlobals.shareScopeMap);
  118. compilation.addRuntimeModule(chunk, new RemoteRuntimeModule());
  119. });
  120. }
  121. );
  122. }
  123. }
  124. module.exports = ContainerReferencePlugin;