webpack 核心编译器 九 节

reportDependencyErrorsAndWarnings(module, blocks)

  • 递归遍历 blocks,获取所有依赖 (dependencies) 的错误 (getErrors()) 和警告 (getWarnings())。
  • 发现问题时,将错误/警告包装成 ModuleDependencyError 或 ModuleDependencyWarning 并存入 this.errors 或 this.warnings,返回 true 表示存在问题。
js 复制代码
	/**
	 * 报告模块及其依赖块中的错误和警告。
	 * @param {Module} module 需要报告的模块
	 * @param {DependenciesBlock[]} blocks 需要报告的依赖块
	 * @returns {boolean} 如果存在警告或错误,则返回 true
	 */
	reportDependencyErrorsAndWarnings(module, blocks) {
		let hasProblems = false;
		for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
			const block = blocks[indexBlock];
			const dependencies = block.dependencies;

			for (let indexDep = 0; indexDep < dependencies.length; indexDep++) {
				const d = dependencies[indexDep];

				// 获取并报告警告
				const warnings = d.getWarnings(this.moduleGraph);
				if (warnings) {
					for (let indexWar = 0; indexWar < warnings.length; indexWar++) {
						const w = warnings[indexWar];

						const warning = new ModuleDependencyWarning(module, w, d.loc);
						this.warnings.push(warning);
						hasProblems = true;
					}
				}

				// 获取并报告错误
				const errors = d.getErrors(this.moduleGraph);
				if (errors) {
					for (let indexErr = 0; indexErr < errors.length; indexErr++) {
						const e = errors[indexErr];

						const error = new ModuleDependencyError(module, e, d.loc);
						this.errors.push(error);
						hasProblems = true;
					}
				}
			}

			// 递归处理子块
			if (this.reportDependencyErrorsAndWarnings(module, block.blocks))
				hasProblems = true;
		}
		return hasProblems;
	}

codeGeneration(callback)

  • 遍历 this.modules,根据模块的 runtime 生成代码哈希 (hash),创建 代码生成任务 (jobs)。
  • 任务交给 _runCodeGenerationJobs 处理。
js 复制代码
	/**
	 * 生成代码。
	 * @param {Callback} callback 回调函数
	 */
	codeGeneration(callback) {
		const { chunkGraph } = this;
		this.codeGenerationResults = new CodeGenerationResults(
			this.outputOptions.hashFunction
		);
		/** @type {CodeGenerationJobs} */
		const jobs = [];
		for (const module of this.modules) {
			const runtimes = chunkGraph.getModuleRuntimes(module);
			if (runtimes.size === 1) {
				for (const runtime of runtimes) {
					const hash = chunkGraph.getModuleHash(module, runtime);
					jobs.push({ module, hash, runtime, runtimes: [runtime] });
				}
			} else if (runtimes.size > 1) {
				/** @type {Map<string, { runtimes: RuntimeSpec[] }>} */
				const map = new Map();
				for (const runtime of runtimes) {
					const hash = chunkGraph.getModuleHash(module, runtime);
					const job = map.get(hash);
					if (job === undefined) {
						const newJob = { module, hash, runtime, runtimes: [runtime] };
						jobs.push(newJob);
						map.set(hash, newJob);
					} else {
						job.runtimes.push(runtime);
					}
				}
			}
		}

		this._runCodeGenerationJobs(jobs, callback);
	}

_runCodeGenerationJobs(jobs, callback)

  • 采用 并行异步任务 (asyncLib.eachLimit()) 执行代码生成,优化并行度 (this.options.parallelism)。
  • 处理代码依赖 (codeGenerationDependencies),防止 循环依赖问题,避免死锁。
  • 记录 缓存命中 和 实际生成 的模块数,优化构建性能。
  • 发生循环依赖时,抛出错误:
js 复制代码
	/**
	 * @private
	 * 执行代码生成任务。
	 * @param {CodeGenerationJobs} jobs 代码生成任务
	 * @param {Callback} callback 回调函数
	 * @returns {void}
	 */
	_runCodeGenerationJobs(jobs, callback) {
		if (jobs.length === 0) {
			return callback();
		}
		let statModulesFromCache = 0;
		let statModulesGenerated = 0;
		const { chunkGraph, moduleGraph, dependencyTemplates, runtimeTemplate } =
			this;
		const results = this.codeGenerationResults;
		/** @type {WebpackError[]} */
		const errors = [];
		/** @type {NotCodeGeneratedModules | undefined} */
		let notCodeGeneratedModules;
		const runIteration = () => {
			/** @type {CodeGenerationJobs} */
			let delayedJobs = [];
			let delayedModules = new Set();
			asyncLib.eachLimit(
				jobs,
				/** @type {number} */
				(this.options.parallelism),
				(job, callback) => {
					const { module } = job;
					const { codeGenerationDependencies } = module;
					if (
						codeGenerationDependencies !== undefined &&
						(notCodeGeneratedModules === undefined ||
							codeGenerationDependencies.some(dep => {
								const referencedModule = /** @type {Module} */ (
									moduleGraph.getModule(dep)
								);
								return /** @type {NotCodeGeneratedModules} */ (
									notCodeGeneratedModules
								).has(referencedModule);
							})
						)
					) {
						delayedJobs.push(job);
						delayedModules.add(module);
						return callback();
					}
					const { hash, runtime, runtimes } = job;
					this._codeGenerationModule(
						module,
						runtime,
						runtimes,
						hash,
						dependencyTemplates,
						chunkGraph,
						moduleGraph,
						runtimeTemplate,
						errors,
						results,
						(err, codeGenerated) => {
							if (codeGenerated) statModulesGenerated++;
							else statModulesFromCache++;
							callback(err);
						}
					);
				},
				err => {
					if (err) return callback(err);
					callback();
				}
			);
		};
		runIteration();
	}
相关推荐
anxiao_m11 分钟前
水利数字孪生怎么选?主流可视化渲染平台深度横向测评
大数据·前端·人工智能·图形渲染·云渲染
kill52220 分钟前
useRef
前端·javascript·react.js
蓝悦无人机22 分钟前
从“摸形状“到“点到线面的距离“——聊聊 SLAM 前端(激光雷达篇)
前端·loam·数据关联·激光slam·点云特征提取·点到线面距离·icp/ndt
flash俊杰1 小时前
工程约束怎么不拖后腿
前端
霍营_托尼1 小时前
纯前端播 40GB 本地视频?我把浏览器改造成了「磁盘流式」播放器
前端·javascript·音视频开发
溪语流沙1 小时前
【Web全栈进阶】FastAPI工程化:APIRouter拆分 + 配置 + 依赖注入
java·前端·fastapi
Shirley~~1 小时前
Three.js的基础概念
前端·3d
deli0071 小时前
黏菌没有大脑,3000 个 Physarum 粒子跑 12973 步自己铺出了迷宫最短路
前端
凌云若寒1 小时前
BarTender提示#807错误:无法在拥有其他许可证的Licensing Service上激活节点锁定的 Professional 版许可证 的解决办法
运维·服务器·前端·学习·软件需求
嘟嘟同学和妮妮同学1 小时前
用原生 JS 做了一个中国历史帝皇梳理的可视化站(7 朝 77 帝 + Leaflet 地图)
前端