source: imaps-frontend/node_modules/webpack/lib/container/HoistContainerReferencesPlugin.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Zackary Jackson @ScriptedAlchemy
4*/
5
6"use strict";
7
8const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
9const ExternalModule = require("../ExternalModule");
10const { STAGE_ADVANCED } = require("../OptimizationStages");
11const memoize = require("../util/memoize");
12const { forEachRuntime } = require("../util/runtime");
13
14/** @typedef {import("../Compilation")} Compilation */
15/** @typedef {import("../Compiler")} Compiler */
16/** @typedef {import("../Dependency")} Dependency */
17/** @typedef {import("../Module")} Module */
18
19const getModuleFederationPlugin = memoize(() =>
20 require("./ModuleFederationPlugin")
21);
22
23const PLUGIN_NAME = "HoistContainerReferences";
24
25/**
26 * This class is used to hoist container references in the code.
27 */
28class HoistContainerReferences {
29 /**
30 * Apply the plugin to the compiler.
31 * @param {Compiler} compiler The webpack compiler instance.
32 */
33 apply(compiler) {
34 compiler.hooks.thisCompilation.tap(PLUGIN_NAME, compilation => {
35 const hooks =
36 getModuleFederationPlugin().getCompilationHooks(compilation);
37 const depsToTrace = new Set();
38 const entryExternalsToHoist = new Set();
39 hooks.addContainerEntryDependency.tap(PLUGIN_NAME, dep => {
40 depsToTrace.add(dep);
41 });
42 hooks.addFederationRuntimeDependency.tap(PLUGIN_NAME, dep => {
43 depsToTrace.add(dep);
44 });
45
46 compilation.hooks.addEntry.tap(PLUGIN_NAME, entryDep => {
47 if (entryDep.type === "entry") {
48 entryExternalsToHoist.add(entryDep);
49 }
50 });
51
52 // Hook into the optimizeChunks phase
53 compilation.hooks.optimizeChunks.tap(
54 {
55 name: PLUGIN_NAME,
56 // advanced stage is where SplitChunksPlugin runs.
57 stage: STAGE_ADVANCED + 1
58 },
59 chunks => {
60 this.hoistModulesInChunks(
61 compilation,
62 depsToTrace,
63 entryExternalsToHoist
64 );
65 }
66 );
67 });
68 }
69
70 /**
71 * Hoist modules in chunks.
72 * @param {Compilation} compilation The webpack compilation instance.
73 * @param {Set<Dependency>} depsToTrace Set of container entry dependencies.
74 * @param {Set<Dependency>} entryExternalsToHoist Set of container entry dependencies to hoist.
75 */
76 hoistModulesInChunks(compilation, depsToTrace, entryExternalsToHoist) {
77 const { chunkGraph, moduleGraph } = compilation;
78
79 // loop over entry points
80 for (const dep of entryExternalsToHoist) {
81 const entryModule = moduleGraph.getModule(dep);
82 if (!entryModule) continue;
83 // get all the external module types and hoist them to the runtime chunk, this will get RemoteModule externals
84 const allReferencedModules = getAllReferencedModules(
85 compilation,
86 entryModule,
87 "external",
88 false
89 );
90
91 const containerRuntimes = chunkGraph.getModuleRuntimes(entryModule);
92 const runtimes = new Set();
93
94 for (const runtimeSpec of containerRuntimes) {
95 forEachRuntime(runtimeSpec, runtimeKey => {
96 if (runtimeKey) {
97 runtimes.add(runtimeKey);
98 }
99 });
100 }
101
102 for (const runtime of runtimes) {
103 const runtimeChunk = compilation.namedChunks.get(runtime);
104 if (!runtimeChunk) continue;
105
106 for (const module of allReferencedModules) {
107 if (!chunkGraph.isModuleInChunk(module, runtimeChunk)) {
108 chunkGraph.connectChunkAndModule(runtimeChunk, module);
109 }
110 }
111 }
112 this.cleanUpChunks(compilation, allReferencedModules);
113 }
114
115 // handle container entry specifically
116 for (const dep of depsToTrace) {
117 const containerEntryModule = moduleGraph.getModule(dep);
118 if (!containerEntryModule) continue;
119 const allReferencedModules = getAllReferencedModules(
120 compilation,
121 containerEntryModule,
122 "initial",
123 false
124 );
125
126 const allRemoteReferences = getAllReferencedModules(
127 compilation,
128 containerEntryModule,
129 "external",
130 false
131 );
132
133 for (const remote of allRemoteReferences) {
134 allReferencedModules.add(remote);
135 }
136
137 const containerRuntimes =
138 chunkGraph.getModuleRuntimes(containerEntryModule);
139 const runtimes = new Set();
140
141 for (const runtimeSpec of containerRuntimes) {
142 forEachRuntime(runtimeSpec, runtimeKey => {
143 if (runtimeKey) {
144 runtimes.add(runtimeKey);
145 }
146 });
147 }
148
149 for (const runtime of runtimes) {
150 const runtimeChunk = compilation.namedChunks.get(runtime);
151 if (!runtimeChunk) continue;
152
153 for (const module of allReferencedModules) {
154 if (!chunkGraph.isModuleInChunk(module, runtimeChunk)) {
155 chunkGraph.connectChunkAndModule(runtimeChunk, module);
156 }
157 }
158 }
159 this.cleanUpChunks(compilation, allReferencedModules);
160 }
161 }
162
163 /**
164 * Clean up chunks by disconnecting unused modules.
165 * @param {Compilation} compilation The webpack compilation instance.
166 * @param {Set<Module>} modules Set of modules to clean up.
167 */
168 cleanUpChunks(compilation, modules) {
169 const { chunkGraph } = compilation;
170 for (const module of modules) {
171 for (const chunk of chunkGraph.getModuleChunks(module)) {
172 if (!chunk.hasRuntime()) {
173 chunkGraph.disconnectChunkAndModule(chunk, module);
174 if (
175 chunkGraph.getNumberOfChunkModules(chunk) === 0 &&
176 chunkGraph.getNumberOfEntryModules(chunk) === 0
177 ) {
178 chunkGraph.disconnectChunk(chunk);
179 compilation.chunks.delete(chunk);
180 if (chunk.name) {
181 compilation.namedChunks.delete(chunk.name);
182 }
183 }
184 }
185 }
186 }
187 modules.clear();
188 }
189}
190
191/**
192 * Helper method to collect all referenced modules recursively.
193 * @param {Compilation} compilation The webpack compilation instance.
194 * @param {Module} module The module to start collecting from.
195 * @param {string} type The type of modules to collect ("initial", "external", or "all").
196 * @param {boolean} includeInitial Should include the referenced module passed
197 * @returns {Set<Module>} Set of collected modules.
198 */
199function getAllReferencedModules(compilation, module, type, includeInitial) {
200 const collectedModules = new Set(includeInitial ? [module] : []);
201 const visitedModules = new WeakSet([module]);
202 const stack = [module];
203
204 while (stack.length > 0) {
205 const currentModule = stack.pop();
206 if (!currentModule) continue;
207
208 const outgoingConnections =
209 compilation.moduleGraph.getOutgoingConnections(currentModule);
210 if (outgoingConnections) {
211 for (const connection of outgoingConnections) {
212 const connectedModule = connection.module;
213
214 // Skip if module has already been visited
215 if (!connectedModule || visitedModules.has(connectedModule)) {
216 continue;
217 }
218
219 // Handle 'initial' type (skipping async blocks)
220 if (type === "initial") {
221 const parentBlock = compilation.moduleGraph.getParentBlock(
222 /** @type {Dependency} */
223 (connection.dependency)
224 );
225 if (parentBlock instanceof AsyncDependenciesBlock) {
226 continue;
227 }
228 }
229
230 // Handle 'external' type (collecting only external modules)
231 if (type === "external") {
232 if (connection.module instanceof ExternalModule) {
233 collectedModules.add(connectedModule);
234 }
235 } else {
236 // Handle 'all' or unspecified types
237 collectedModules.add(connectedModule);
238 }
239
240 // Add connected module to the stack and mark it as visited
241 visitedModules.add(connectedModule);
242 stack.push(connectedModule);
243 }
244 }
245 }
246
247 return collectedModules;
248}
249
250module.exports = HoistContainerReferences;
Note: See TracBrowser for help on using the repository browser.