Buckets:
ktongue/docker_container / CAD_kevin /frontend /node_modules /webpack /lib /FlagDependencyUsagePlugin.js
| /* | |
| MIT License http://www.opensource.org/licenses/mit-license.php | |
| Author Tobias Koppers @sokra | |
| */ | |
| ; | |
| const Dependency = require("./Dependency"); | |
| const { UsageState } = require("./ExportsInfo"); | |
| const ModuleGraphConnection = require("./ModuleGraphConnection"); | |
| const { STAGE_DEFAULT } = require("./OptimizationStages"); | |
| const ArrayQueue = require("./util/ArrayQueue"); | |
| const TupleQueue = require("./util/TupleQueue"); | |
| const { getEntryRuntime, mergeRuntimeOwned } = require("./util/runtime"); | |
| /** @typedef {import("./Compiler")} Compiler */ | |
| /** @typedef {import("./DependenciesBlock")} DependenciesBlock */ | |
| /** @typedef {import("./Dependency").ReferencedExport} ReferencedExport */ | |
| /** @typedef {import("./Dependency").ReferencedExports} ReferencedExports */ | |
| /** @typedef {import("./ExportsInfo")} ExportsInfo */ | |
| /** @typedef {import("./Module")} Module */ | |
| /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */ | |
| const { NO_EXPORTS_REFERENCED, EXPORTS_OBJECT_REFERENCED } = Dependency; | |
| const PLUGIN_NAME = "FlagDependencyUsagePlugin"; | |
| const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`; | |
| class FlagDependencyUsagePlugin { | |
| /** | |
| * @param {boolean} global do a global analysis instead of per runtime | |
| */ | |
| constructor(global) { | |
| /** @type {boolean} */ | |
| this.global = global; | |
| } | |
| /** | |
| * Apply the plugin | |
| * @param {Compiler} compiler the compiler instance | |
| * @returns {void} | |
| */ | |
| apply(compiler) { | |
| compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { | |
| const moduleGraph = compilation.moduleGraph; | |
| compilation.hooks.optimizeDependencies.tap( | |
| { name: PLUGIN_NAME, stage: STAGE_DEFAULT }, | |
| (modules) => { | |
| if (compilation.moduleMemCaches) { | |
| throw new Error( | |
| "optimization.usedExports can't be used with cacheUnaffected as export usage is a global effect" | |
| ); | |
| } | |
| const logger = compilation.getLogger(PLUGIN_LOGGER_NAME); | |
| /** @type {Map<ExportsInfo, Module>} */ | |
| const exportInfoToModuleMap = new Map(); | |
| /** @type {TupleQueue<Module, RuntimeSpec>} */ | |
| const queue = new TupleQueue(); | |
| /** | |
| * @param {Module} module module to process | |
| * @param {ReferencedExports} usedExports list of used exports | |
| * @param {RuntimeSpec} runtime part of which runtime | |
| * @param {boolean} forceSideEffects always apply side effects | |
| * @returns {void} | |
| */ | |
| const processReferencedModule = ( | |
| module, | |
| usedExports, | |
| runtime, | |
| forceSideEffects | |
| ) => { | |
| const exportsInfo = moduleGraph.getExportsInfo(module); | |
| if (usedExports.length > 0) { | |
| if (!module.buildMeta || !module.buildMeta.exportsType) { | |
| if (exportsInfo.setUsedWithoutInfo(runtime)) { | |
| queue.enqueue(module, runtime); | |
| } | |
| return; | |
| } | |
| for (const usedExportInfo of usedExports) { | |
| /** @type {string[]} */ | |
| let usedExport; | |
| let canMangle = true; | |
| if (Array.isArray(usedExportInfo)) { | |
| usedExport = usedExportInfo; | |
| } else { | |
| usedExport = usedExportInfo.name; | |
| canMangle = usedExportInfo.canMangle !== false; | |
| } | |
| if (usedExport.length === 0) { | |
| if (exportsInfo.setUsedInUnknownWay(runtime)) { | |
| queue.enqueue(module, runtime); | |
| } | |
| } else { | |
| let currentExportsInfo = exportsInfo; | |
| for (let i = 0; i < usedExport.length; i++) { | |
| const exportInfo = currentExportsInfo.getExportInfo( | |
| usedExport[i] | |
| ); | |
| if (canMangle === false) { | |
| exportInfo.canMangleUse = false; | |
| } | |
| const lastOne = i === usedExport.length - 1; | |
| if (!lastOne) { | |
| const nestedInfo = exportInfo.getNestedExportsInfo(); | |
| if (nestedInfo) { | |
| if ( | |
| exportInfo.setUsedConditionally( | |
| (used) => used === UsageState.Unused, | |
| UsageState.OnlyPropertiesUsed, | |
| runtime | |
| ) | |
| ) { | |
| const currentModule = | |
| currentExportsInfo === exportsInfo | |
| ? module | |
| : exportInfoToModuleMap.get(currentExportsInfo); | |
| if (currentModule) { | |
| queue.enqueue(currentModule, runtime); | |
| } | |
| } | |
| currentExportsInfo = nestedInfo; | |
| continue; | |
| } | |
| } | |
| if ( | |
| exportInfo.setUsedConditionally( | |
| (v) => v !== UsageState.Used, | |
| UsageState.Used, | |
| runtime | |
| ) | |
| ) { | |
| const currentModule = | |
| currentExportsInfo === exportsInfo | |
| ? module | |
| : exportInfoToModuleMap.get(currentExportsInfo); | |
| if (currentModule) { | |
| queue.enqueue(currentModule, runtime); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } else { | |
| // for a module without side effects we stop tracking usage here when no export is used | |
| // This module won't be evaluated in this case | |
| // TODO webpack 6 remove this check | |
| if ( | |
| !forceSideEffects && | |
| module.factoryMeta !== undefined && | |
| module.factoryMeta.sideEffectFree | |
| ) { | |
| return; | |
| } | |
| if (exportsInfo.setUsedForSideEffectsOnly(runtime)) { | |
| queue.enqueue(module, runtime); | |
| } | |
| } | |
| }; | |
| /** | |
| * @param {DependenciesBlock} module the module | |
| * @param {RuntimeSpec} runtime part of which runtime | |
| * @param {boolean} forceSideEffects always apply side effects | |
| * @returns {void} | |
| */ | |
| const processModule = (module, runtime, forceSideEffects) => { | |
| /** @typedef {Map<string, string[] | ReferencedExport>} ExportMaps */ | |
| /** @type {Map<Module, ReferencedExports | ExportMaps>} */ | |
| const map = new Map(); | |
| /** @type {ArrayQueue<DependenciesBlock>} */ | |
| const queue = new ArrayQueue(); | |
| queue.enqueue(module); | |
| for (;;) { | |
| const block = queue.dequeue(); | |
| if (block === undefined) break; | |
| for (const b of block.blocks) { | |
| if (b.groupOptions && b.groupOptions.entryOptions) { | |
| processModule( | |
| b, | |
| this.global | |
| ? undefined | |
| : b.groupOptions.entryOptions.runtime || undefined, | |
| true | |
| ); | |
| } else { | |
| queue.enqueue(b); | |
| } | |
| } | |
| for (const dep of block.dependencies) { | |
| const connection = moduleGraph.getConnection(dep); | |
| if (!connection || !connection.module) { | |
| continue; | |
| } | |
| const activeState = connection.getActiveState(runtime); | |
| if (activeState === false) continue; | |
| const { module } = connection; | |
| if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) { | |
| processModule(module, runtime, false); | |
| continue; | |
| } | |
| const oldReferencedExports = map.get(module); | |
| if (oldReferencedExports === EXPORTS_OBJECT_REFERENCED) { | |
| continue; | |
| } | |
| const referencedExports = | |
| compilation.getDependencyReferencedExports(dep, runtime); | |
| if ( | |
| oldReferencedExports === undefined || | |
| oldReferencedExports === NO_EXPORTS_REFERENCED || | |
| referencedExports === EXPORTS_OBJECT_REFERENCED | |
| ) { | |
| map.set(module, referencedExports); | |
| } else if ( | |
| oldReferencedExports !== undefined && | |
| referencedExports === NO_EXPORTS_REFERENCED | |
| ) { | |
| continue; | |
| } else { | |
| /** @type {undefined | ExportMaps} */ | |
| let exportsMap; | |
| if (Array.isArray(oldReferencedExports)) { | |
| exportsMap = new Map(); | |
| for (const item of oldReferencedExports) { | |
| if (Array.isArray(item)) { | |
| exportsMap.set(item.join("\n"), item); | |
| } else { | |
| exportsMap.set(item.name.join("\n"), item); | |
| } | |
| } | |
| map.set(module, exportsMap); | |
| } else { | |
| exportsMap = oldReferencedExports; | |
| } | |
| for (const item of referencedExports) { | |
| if (Array.isArray(item)) { | |
| const key = item.join("\n"); | |
| const oldItem = exportsMap.get(key); | |
| if (oldItem === undefined) { | |
| exportsMap.set(key, item); | |
| } | |
| // if oldItem is already an array we have to do nothing | |
| // if oldItem is an ReferencedExport object, we don't have to do anything | |
| // as canMangle defaults to true for arrays | |
| } else { | |
| const key = item.name.join("\n"); | |
| const oldItem = exportsMap.get(key); | |
| if (oldItem === undefined || Array.isArray(oldItem)) { | |
| exportsMap.set(key, item); | |
| } else { | |
| exportsMap.set(key, { | |
| name: item.name, | |
| canMangle: item.canMangle && oldItem.canMangle | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| for (const [module, referencedExports] of map) { | |
| if (Array.isArray(referencedExports)) { | |
| processReferencedModule( | |
| module, | |
| referencedExports, | |
| runtime, | |
| forceSideEffects | |
| ); | |
| } else { | |
| processReferencedModule( | |
| module, | |
| [...referencedExports.values()], | |
| runtime, | |
| forceSideEffects | |
| ); | |
| } | |
| } | |
| }; | |
| logger.time("initialize exports usage"); | |
| for (const module of modules) { | |
| const exportsInfo = moduleGraph.getExportsInfo(module); | |
| exportInfoToModuleMap.set(exportsInfo, module); | |
| exportsInfo.setHasUseInfo(); | |
| } | |
| logger.timeEnd("initialize exports usage"); | |
| logger.time("trace exports usage in graph"); | |
| /** | |
| * @param {Dependency} dep dependency | |
| * @param {RuntimeSpec} runtime runtime | |
| */ | |
| const processEntryDependency = (dep, runtime) => { | |
| const module = moduleGraph.getModule(dep); | |
| if (module) { | |
| processReferencedModule( | |
| module, | |
| NO_EXPORTS_REFERENCED, | |
| runtime, | |
| true | |
| ); | |
| } | |
| }; | |
| /** @type {RuntimeSpec} */ | |
| let globalRuntime; | |
| for (const [ | |
| entryName, | |
| { dependencies: deps, includeDependencies: includeDeps, options } | |
| ] of compilation.entries) { | |
| const runtime = this.global | |
| ? undefined | |
| : getEntryRuntime(compilation, entryName, options); | |
| for (const dep of deps) { | |
| processEntryDependency(dep, runtime); | |
| } | |
| for (const dep of includeDeps) { | |
| processEntryDependency(dep, runtime); | |
| } | |
| globalRuntime = mergeRuntimeOwned(globalRuntime, runtime); | |
| } | |
| for (const dep of compilation.globalEntry.dependencies) { | |
| processEntryDependency(dep, globalRuntime); | |
| } | |
| for (const dep of compilation.globalEntry.includeDependencies) { | |
| processEntryDependency(dep, globalRuntime); | |
| } | |
| while (queue.length) { | |
| const [module, runtime] = /** @type {[Module, RuntimeSpec]} */ ( | |
| queue.dequeue() | |
| ); | |
| processModule(module, runtime, false); | |
| } | |
| logger.timeEnd("trace exports usage in graph"); | |
| } | |
| ); | |
| }); | |
| } | |
| } | |
| module.exports = FlagDependencyUsagePlugin; | |
Xet Storage Details
- Size:
- 11.2 kB
- Xet hash:
- f1aadbe6f8b63228bee7260ef7beb57c5a24752f98dcf1c244e73ded596eed53
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.