source: trip-planner-front/node_modules/webpack/lib/FlagDependencyUsagePlugin.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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