source: imaps-frontend/node_modules/webpack/lib/FlagDependencyUsagePlugin.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: 10.8 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 Dependency = require("./Dependency");
9const { UsageState } = require("./ExportsInfo");
10const ModuleGraphConnection = require("./ModuleGraphConnection");
11const { STAGE_DEFAULT } = require("./OptimizationStages");
12const ArrayQueue = require("./util/ArrayQueue");
13const TupleQueue = require("./util/TupleQueue");
14const { getEntryRuntime, mergeRuntimeOwned } = require("./util/runtime");
15
16/** @typedef {import("./Chunk")} Chunk */
17/** @typedef {import("./ChunkGroup")} ChunkGroup */
18/** @typedef {import("./Compiler")} Compiler */
19/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
20/** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */
21/** @typedef {import("./ExportsInfo")} ExportsInfo */
22/** @typedef {import("./Module")} Module */
23/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
24
25const { NO_EXPORTS_REFERENCED, EXPORTS_OBJECT_REFERENCED } = Dependency;
26
27const PLUGIN_NAME = "FlagDependencyUsagePlugin";
28const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`;
29
30class FlagDependencyUsagePlugin {
31 /**
32 * @param {boolean} global do a global analysis instead of per runtime
33 */
34 constructor(global) {
35 this.global = global;
36 }
37
38 /**
39 * Apply the plugin
40 * @param {Compiler} compiler the compiler instance
41 * @returns {void}
42 */
43 apply(compiler) {
44 compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
45 const moduleGraph = compilation.moduleGraph;
46 compilation.hooks.optimizeDependencies.tap(
47 { name: PLUGIN_NAME, stage: STAGE_DEFAULT },
48 modules => {
49 if (compilation.moduleMemCaches) {
50 throw new Error(
51 "optimization.usedExports can't be used with cacheUnaffected as export usage is a global effect"
52 );
53 }
54
55 const logger = compilation.getLogger(PLUGIN_LOGGER_NAME);
56 /** @type {Map<ExportsInfo, Module>} */
57 const exportInfoToModuleMap = new Map();
58
59 /** @type {TupleQueue<[Module, RuntimeSpec]>} */
60 const queue = new TupleQueue();
61
62 /**
63 * @param {Module} module module to process
64 * @param {(string[] | ReferencedExport)[]} usedExports list of used exports
65 * @param {RuntimeSpec} runtime part of which runtime
66 * @param {boolean} forceSideEffects always apply side effects
67 * @returns {void}
68 */
69 const processReferencedModule = (
70 module,
71 usedExports,
72 runtime,
73 forceSideEffects
74 ) => {
75 const exportsInfo = moduleGraph.getExportsInfo(module);
76 if (usedExports.length > 0) {
77 if (!module.buildMeta || !module.buildMeta.exportsType) {
78 if (exportsInfo.setUsedWithoutInfo(runtime)) {
79 queue.enqueue(module, runtime);
80 }
81 return;
82 }
83 for (const usedExportInfo of usedExports) {
84 let usedExport;
85 let canMangle = true;
86 if (Array.isArray(usedExportInfo)) {
87 usedExport = usedExportInfo;
88 } else {
89 usedExport = usedExportInfo.name;
90 canMangle = usedExportInfo.canMangle !== false;
91 }
92 if (usedExport.length === 0) {
93 if (exportsInfo.setUsedInUnknownWay(runtime)) {
94 queue.enqueue(module, runtime);
95 }
96 } else {
97 let currentExportsInfo = exportsInfo;
98 for (let i = 0; i < usedExport.length; i++) {
99 const exportInfo = currentExportsInfo.getExportInfo(
100 usedExport[i]
101 );
102 if (canMangle === false) {
103 exportInfo.canMangleUse = false;
104 }
105 const lastOne = i === usedExport.length - 1;
106 if (!lastOne) {
107 const nestedInfo = exportInfo.getNestedExportsInfo();
108 if (nestedInfo) {
109 if (
110 exportInfo.setUsedConditionally(
111 used => used === UsageState.Unused,
112 UsageState.OnlyPropertiesUsed,
113 runtime
114 )
115 ) {
116 const currentModule =
117 currentExportsInfo === exportsInfo
118 ? module
119 : exportInfoToModuleMap.get(currentExportsInfo);
120 if (currentModule) {
121 queue.enqueue(currentModule, runtime);
122 }
123 }
124 currentExportsInfo = nestedInfo;
125 continue;
126 }
127 }
128 if (
129 exportInfo.setUsedConditionally(
130 v => v !== UsageState.Used,
131 UsageState.Used,
132 runtime
133 )
134 ) {
135 const currentModule =
136 currentExportsInfo === exportsInfo
137 ? module
138 : exportInfoToModuleMap.get(currentExportsInfo);
139 if (currentModule) {
140 queue.enqueue(currentModule, runtime);
141 }
142 }
143 break;
144 }
145 }
146 }
147 } else {
148 // for a module without side effects we stop tracking usage here when no export is used
149 // This module won't be evaluated in this case
150 // TODO webpack 6 remove this check
151 if (
152 !forceSideEffects &&
153 module.factoryMeta !== undefined &&
154 module.factoryMeta.sideEffectFree
155 ) {
156 return;
157 }
158 if (exportsInfo.setUsedForSideEffectsOnly(runtime)) {
159 queue.enqueue(module, runtime);
160 }
161 }
162 };
163
164 /**
165 * @param {DependenciesBlock} module the module
166 * @param {RuntimeSpec} runtime part of which runtime
167 * @param {boolean} forceSideEffects always apply side effects
168 * @returns {void}
169 */
170 const processModule = (module, runtime, forceSideEffects) => {
171 /** @type {Map<Module, (string[] | ReferencedExport)[] | Map<string, string[] | ReferencedExport>>} */
172 const map = new Map();
173
174 /** @type {ArrayQueue<DependenciesBlock>} */
175 const queue = new ArrayQueue();
176 queue.enqueue(module);
177 for (;;) {
178 const block = queue.dequeue();
179 if (block === undefined) break;
180 for (const b of block.blocks) {
181 if (
182 !this.global &&
183 b.groupOptions &&
184 b.groupOptions.entryOptions
185 ) {
186 processModule(
187 b,
188 b.groupOptions.entryOptions.runtime || undefined,
189 true
190 );
191 } else {
192 queue.enqueue(b);
193 }
194 }
195 for (const dep of block.dependencies) {
196 const connection = moduleGraph.getConnection(dep);
197 if (!connection || !connection.module) {
198 continue;
199 }
200 const activeState = connection.getActiveState(runtime);
201 if (activeState === false) continue;
202 const { module } = connection;
203 if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) {
204 processModule(module, runtime, false);
205 continue;
206 }
207 const oldReferencedExports = map.get(module);
208 if (oldReferencedExports === EXPORTS_OBJECT_REFERENCED) {
209 continue;
210 }
211 const referencedExports =
212 compilation.getDependencyReferencedExports(dep, runtime);
213 if (
214 oldReferencedExports === undefined ||
215 oldReferencedExports === NO_EXPORTS_REFERENCED ||
216 referencedExports === EXPORTS_OBJECT_REFERENCED
217 ) {
218 map.set(module, referencedExports);
219 } else if (
220 oldReferencedExports !== undefined &&
221 referencedExports === NO_EXPORTS_REFERENCED
222 ) {
223 continue;
224 } else {
225 let exportsMap;
226 if (Array.isArray(oldReferencedExports)) {
227 exportsMap = new Map();
228 for (const item of oldReferencedExports) {
229 if (Array.isArray(item)) {
230 exportsMap.set(item.join("\n"), item);
231 } else {
232 exportsMap.set(item.name.join("\n"), item);
233 }
234 }
235 map.set(module, exportsMap);
236 } else {
237 exportsMap = oldReferencedExports;
238 }
239 for (const item of referencedExports) {
240 if (Array.isArray(item)) {
241 const key = item.join("\n");
242 const oldItem = exportsMap.get(key);
243 if (oldItem === undefined) {
244 exportsMap.set(key, item);
245 }
246 // if oldItem is already an array we have to do nothing
247 // if oldItem is an ReferencedExport object, we don't have to do anything
248 // as canMangle defaults to true for arrays
249 } else {
250 const key = item.name.join("\n");
251 const oldItem = exportsMap.get(key);
252 if (oldItem === undefined || Array.isArray(oldItem)) {
253 exportsMap.set(key, item);
254 } else {
255 exportsMap.set(key, {
256 name: item.name,
257 canMangle: item.canMangle && oldItem.canMangle
258 });
259 }
260 }
261 }
262 }
263 }
264 }
265
266 for (const [module, referencedExports] of map) {
267 if (Array.isArray(referencedExports)) {
268 processReferencedModule(
269 module,
270 referencedExports,
271 runtime,
272 forceSideEffects
273 );
274 } else {
275 processReferencedModule(
276 module,
277 Array.from(referencedExports.values()),
278 runtime,
279 forceSideEffects
280 );
281 }
282 }
283 };
284
285 logger.time("initialize exports usage");
286 for (const module of modules) {
287 const exportsInfo = moduleGraph.getExportsInfo(module);
288 exportInfoToModuleMap.set(exportsInfo, module);
289 exportsInfo.setHasUseInfo();
290 }
291 logger.timeEnd("initialize exports usage");
292
293 logger.time("trace exports usage in graph");
294
295 /**
296 * @param {Dependency} dep dependency
297 * @param {RuntimeSpec} runtime runtime
298 */
299 const processEntryDependency = (dep, runtime) => {
300 const module = moduleGraph.getModule(dep);
301 if (module) {
302 processReferencedModule(
303 module,
304 NO_EXPORTS_REFERENCED,
305 runtime,
306 true
307 );
308 }
309 };
310 /** @type {RuntimeSpec} */
311 let globalRuntime;
312 for (const [
313 entryName,
314 { dependencies: deps, includeDependencies: includeDeps, options }
315 ] of compilation.entries) {
316 const runtime = this.global
317 ? undefined
318 : getEntryRuntime(compilation, entryName, options);
319 for (const dep of deps) {
320 processEntryDependency(dep, runtime);
321 }
322 for (const dep of includeDeps) {
323 processEntryDependency(dep, runtime);
324 }
325 globalRuntime = mergeRuntimeOwned(globalRuntime, runtime);
326 }
327 for (const dep of compilation.globalEntry.dependencies) {
328 processEntryDependency(dep, globalRuntime);
329 }
330 for (const dep of compilation.globalEntry.includeDependencies) {
331 processEntryDependency(dep, globalRuntime);
332 }
333
334 while (queue.length) {
335 const [module, runtime] = /** @type {[Module, RuntimeSpec]} */ (
336 queue.dequeue()
337 );
338 processModule(module, runtime, false);
339 }
340 logger.timeEnd("trace exports usage in graph");
341 }
342 );
343 });
344 }
345}
346
347module.exports = FlagDependencyUsagePlugin;
Note: See TracBrowser for help on using the repository browser.