ContainerReferencePlugin.js 4.2 KB

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