source: frontend/node_modules/webpack/lib/FlagDependencyExportsPlugin.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 13.7 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const asyncLib = require("neo-async");
9const Queue = require("./util/Queue");
10
11/** @typedef {import("./Compiler")} Compiler */
12/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
13/** @typedef {import("./Dependency")} Dependency */
14/** @typedef {import("./Dependency").ExportSpec} ExportSpec */
15/** @typedef {import("./Dependency").ExportsSpec} ExportsSpec */
16/** @typedef {import("./ExportsInfo")} ExportsInfo */
17/** @typedef {import("./ExportsInfo").ExportInfoName} ExportInfoName */
18/** @typedef {import("./ExportsInfo").RestoreProvidedData} RestoreProvidedData */
19/** @typedef {import("./Module")} Module */
20/** @typedef {import("./Module").BuildInfo} BuildInfo */
21
22const PLUGIN_NAME = "FlagDependencyExportsPlugin";
23const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`;
24
25class FlagDependencyExportsPlugin {
26 /**
27 * Applies the plugin by registering its hooks on the compiler.
28 * @param {Compiler} compiler the compiler instance
29 * @returns {void}
30 */
31 apply(compiler) {
32 compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
33 const moduleGraph = compilation.moduleGraph;
34 const cache = compilation.getCache(PLUGIN_NAME);
35 compilation.hooks.finishModules.tapAsync(
36 PLUGIN_NAME,
37 (modules, callback) => {
38 const logger = compilation.getLogger(PLUGIN_LOGGER_NAME);
39 let statRestoredFromMemCache = 0;
40 let statRestoredFromCache = 0;
41 let statNoExports = 0;
42 let statFlaggedUncached = 0;
43 let statNotCached = 0;
44 let statQueueItemsProcessed = 0;
45
46 const { moduleMemCaches } = compilation;
47
48 /** @type {Queue<Module>} */
49 const queue = new Queue();
50
51 // Step 1: Try to restore cached provided export info from cache
52 logger.time("restore cached provided exports");
53 asyncLib.each(
54 /** @type {import("neo-async").IterableCollection<Module>} */ (
55 /** @type {unknown} */ (modules)
56 ),
57 (module, callback) => {
58 const exportsInfo = moduleGraph.getExportsInfo(module);
59 // If the module doesn't have an exportsType, it's a module
60 // without declared exports.
61 if (
62 (!module.buildMeta || !module.buildMeta.exportsType) &&
63 exportsInfo.otherExportsInfo.provided !== null
64 ) {
65 // It's a module without declared exports
66 statNoExports++;
67 exportsInfo.setHasProvideInfo();
68 exportsInfo.setUnknownExportsProvided();
69 return callback();
70 }
71 // If the module has no hash, it's uncacheable
72 if (
73 typeof (/** @type {BuildInfo} */ (module.buildInfo).hash) !==
74 "string"
75 ) {
76 statFlaggedUncached++;
77 // Enqueue uncacheable module for determining the exports
78 queue.enqueue(module);
79 exportsInfo.setHasProvideInfo();
80 return callback();
81 }
82 const memCache = moduleMemCaches && moduleMemCaches.get(module);
83 const memCacheValue = memCache && memCache.get(this);
84 if (memCacheValue !== undefined) {
85 statRestoredFromMemCache++;
86 exportsInfo.restoreProvided(memCacheValue);
87 return callback();
88 }
89 cache.get(
90 module.identifier(),
91 /** @type {BuildInfo} */
92 (module.buildInfo).hash,
93 (err, result) => {
94 if (err) return callback(err);
95
96 if (result !== undefined) {
97 statRestoredFromCache++;
98 exportsInfo.restoreProvided(result);
99 } else {
100 statNotCached++;
101 // Without cached info enqueue module for determining the exports
102 queue.enqueue(module);
103 exportsInfo.setHasProvideInfo();
104 }
105 callback();
106 }
107 );
108 },
109 (err) => {
110 logger.timeEnd("restore cached provided exports");
111 if (err) return callback(err);
112
113 /** @type {Set<Module>} */
114 const modulesToStore = new Set();
115
116 /** @type {Map<Module, Set<Module>>} */
117 const dependencies = new Map();
118
119 /** @type {Module} */
120 let module;
121
122 /** @type {ExportsInfo} */
123 let exportsInfo;
124
125 /** @type {Map<Dependency, ExportsSpec>} */
126 const exportsSpecsFromDependencies = new Map();
127
128 let cacheable = true;
129 let changed = false;
130
131 /**
132 * Process dependencies block.
133 * @param {DependenciesBlock} depBlock the dependencies block
134 * @returns {void}
135 */
136 const processDependenciesBlock = (depBlock) => {
137 for (const dep of depBlock.dependencies) {
138 processDependency(dep);
139 }
140 for (const block of depBlock.blocks) {
141 processDependenciesBlock(block);
142 }
143 };
144
145 /**
146 * Process dependency.
147 * @param {Dependency} dep the dependency
148 * @returns {void}
149 */
150 const processDependency = (dep) => {
151 const exportDesc = dep.getExports(moduleGraph);
152 if (!exportDesc) return;
153 exportsSpecsFromDependencies.set(dep, exportDesc);
154 };
155
156 /**
157 * Process exports spec.
158 * @param {Dependency} dep dependency
159 * @param {ExportsSpec} exportDesc info
160 * @returns {void}
161 */
162 const processExportsSpec = (dep, exportDesc) => {
163 const exports = exportDesc.exports;
164 const globalCanMangle = exportDesc.canMangle;
165 const globalFrom = exportDesc.from;
166 const globalPriority = exportDesc.priority;
167 const globalTerminalBinding =
168 exportDesc.terminalBinding || false;
169 const exportDeps = exportDesc.dependencies;
170 if (exportDesc.hideExports) {
171 for (const name of exportDesc.hideExports) {
172 const exportInfo = exportsInfo.getExportInfo(name);
173 exportInfo.unsetTarget(dep);
174 }
175 }
176 if (exports === true) {
177 // unknown exports
178 if (
179 exportsInfo.setUnknownExportsProvided(
180 globalCanMangle,
181 exportDesc.excludeExports,
182 globalFrom && dep,
183 globalFrom,
184 globalPriority
185 )
186 ) {
187 changed = true;
188 }
189 } else if (Array.isArray(exports)) {
190 /**
191 * merge in new exports
192 * @param {ExportsInfo} exportsInfo own exports info
193 * @param {(ExportSpec | string)[]} exports list of exports
194 */
195 const mergeExports = (exportsInfo, exports) => {
196 for (const exportNameOrSpec of exports) {
197 /** @type {ExportInfoName} */
198 let name;
199 let canMangle = globalCanMangle;
200 let terminalBinding = globalTerminalBinding;
201 /** @type {ExportSpec["exports"]} */
202 let exports;
203 let from = globalFrom;
204 /** @type {ExportSpec["export"]} */
205 let fromExport;
206 let priority = globalPriority;
207 let hidden = false;
208 if (typeof exportNameOrSpec === "string") {
209 name = exportNameOrSpec;
210 } else {
211 name = exportNameOrSpec.name;
212 if (exportNameOrSpec.canMangle !== undefined) {
213 canMangle = exportNameOrSpec.canMangle;
214 }
215 if (exportNameOrSpec.export !== undefined) {
216 fromExport = exportNameOrSpec.export;
217 }
218 if (exportNameOrSpec.exports !== undefined) {
219 exports = exportNameOrSpec.exports;
220 }
221 if (exportNameOrSpec.from !== undefined) {
222 from = exportNameOrSpec.from;
223 }
224 if (exportNameOrSpec.priority !== undefined) {
225 priority = exportNameOrSpec.priority;
226 }
227 if (exportNameOrSpec.terminalBinding !== undefined) {
228 terminalBinding = exportNameOrSpec.terminalBinding;
229 }
230 if (exportNameOrSpec.hidden !== undefined) {
231 hidden = exportNameOrSpec.hidden;
232 }
233 }
234 const exportInfo = exportsInfo.getExportInfo(name);
235
236 if (
237 exportInfo.provided === false ||
238 exportInfo.provided === null
239 ) {
240 exportInfo.provided = true;
241 changed = true;
242 }
243
244 if (
245 exportInfo.canMangleProvide !== false &&
246 canMangle === false
247 ) {
248 exportInfo.canMangleProvide = false;
249 changed = true;
250 }
251
252 if (terminalBinding && !exportInfo.terminalBinding) {
253 exportInfo.terminalBinding = true;
254 changed = true;
255 }
256
257 if (exports) {
258 const nestedExportsInfo =
259 exportInfo.createNestedExportsInfo();
260 mergeExports(
261 /** @type {ExportsInfo} */ (nestedExportsInfo),
262 exports
263 );
264 }
265
266 if (
267 from &&
268 (hidden
269 ? exportInfo.unsetTarget(dep)
270 : exportInfo.setTarget(
271 dep,
272 from,
273 fromExport === undefined ? [name] : fromExport,
274 priority
275 ))
276 ) {
277 changed = true;
278 }
279
280 // Recalculate target exportsInfo
281 const target = exportInfo.getTarget(moduleGraph);
282 /** @type {undefined | ExportsInfo} */
283 let targetExportsInfo;
284 if (target) {
285 const targetModuleExportsInfo =
286 moduleGraph.getExportsInfo(target.module);
287 targetExportsInfo =
288 targetModuleExportsInfo.getNestedExportsInfo(
289 target.export
290 );
291 // add dependency for this module
292 const set = dependencies.get(target.module);
293 if (set === undefined) {
294 dependencies.set(target.module, new Set([module]));
295 } else {
296 set.add(module);
297 }
298 }
299
300 if (exportInfo.exportsInfoOwned) {
301 if (
302 /** @type {ExportsInfo} */
303 (exportInfo.exportsInfo).setRedirectNamedTo(
304 targetExportsInfo
305 )
306 ) {
307 changed = true;
308 }
309 } else if (exportInfo.exportsInfo !== targetExportsInfo) {
310 exportInfo.exportsInfo = targetExportsInfo;
311 changed = true;
312 }
313 }
314 };
315 mergeExports(exportsInfo, exports);
316 }
317 // store dependencies
318 if (exportDeps) {
319 cacheable = false;
320 for (const exportDependency of exportDeps) {
321 // add dependency for this module
322 const set = dependencies.get(exportDependency);
323 if (set === undefined) {
324 dependencies.set(exportDependency, new Set([module]));
325 } else {
326 set.add(module);
327 }
328 }
329 }
330 };
331
332 const notifyDependencies = () => {
333 const deps = dependencies.get(module);
334 if (deps !== undefined) {
335 for (const dep of deps) {
336 queue.enqueue(dep);
337 }
338 }
339 };
340
341 logger.time("figure out provided exports");
342 while (queue.length > 0) {
343 module = /** @type {Module} */ (queue.dequeue());
344
345 statQueueItemsProcessed++;
346
347 exportsInfo = moduleGraph.getExportsInfo(module);
348
349 cacheable = true;
350 changed = false;
351
352 exportsSpecsFromDependencies.clear();
353 moduleGraph.freeze();
354 processDependenciesBlock(module);
355 moduleGraph.unfreeze();
356 for (const [dep, exportsSpec] of exportsSpecsFromDependencies) {
357 processExportsSpec(dep, exportsSpec);
358 }
359
360 if (cacheable) {
361 modulesToStore.add(module);
362 }
363
364 if (changed) {
365 notifyDependencies();
366 }
367 }
368 logger.timeEnd("figure out provided exports");
369
370 logger.log(
371 `${Math.round(
372 (100 * (statFlaggedUncached + statNotCached)) /
373 (statRestoredFromMemCache +
374 statRestoredFromCache +
375 statNotCached +
376 statFlaggedUncached +
377 statNoExports)
378 )}% of exports of modules have been determined (${statNoExports} no declared exports, ${statNotCached} not cached, ${statFlaggedUncached} flagged uncacheable, ${statRestoredFromCache} from cache, ${statRestoredFromMemCache} from mem cache, ${
379 statQueueItemsProcessed - statNotCached - statFlaggedUncached
380 } additional calculations due to dependencies)`
381 );
382
383 logger.time("store provided exports into cache");
384 asyncLib.each(
385 modulesToStore,
386 (module, callback) => {
387 if (
388 typeof (
389 /** @type {BuildInfo} */
390 (module.buildInfo).hash
391 ) !== "string"
392 ) {
393 // not cacheable
394 return callback();
395 }
396 const cachedData = moduleGraph
397 .getExportsInfo(module)
398 .getRestoreProvidedData();
399 const memCache =
400 moduleMemCaches && moduleMemCaches.get(module);
401 if (memCache) {
402 memCache.set(this, cachedData);
403 }
404 cache.store(
405 module.identifier(),
406 /** @type {BuildInfo} */
407 (module.buildInfo).hash,
408 cachedData,
409 callback
410 );
411 },
412 (err) => {
413 logger.timeEnd("store provided exports into cache");
414 callback(err);
415 }
416 );
417 }
418 );
419 }
420 );
421
422 /** @type {WeakMap<Module, RestoreProvidedData>} */
423 const providedExportsCache = new WeakMap();
424 compilation.hooks.rebuildModule.tap(PLUGIN_NAME, (module) => {
425 providedExportsCache.set(
426 module,
427 moduleGraph.getExportsInfo(module).getRestoreProvidedData()
428 );
429 });
430 compilation.hooks.finishRebuildingModule.tap(PLUGIN_NAME, (module) => {
431 moduleGraph.getExportsInfo(module).restoreProvided(
432 /** @type {RestoreProvidedData} */
433 (providedExportsCache.get(module))
434 );
435 });
436 });
437 }
438}
439
440module.exports = FlagDependencyExportsPlugin;
Note: See TracBrowser for help on using the repository browser.