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

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

F4 Finalna Verzija

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