webpack 核心编译器 九 节

reportDependencyErrorsAndWarnings(module, blocks)

  • 递归遍历 blocks,获取所有依赖 (dependencies) 的错误 (getErrors()) 和警告 (getWarnings())。
  • 发现问题时,将错误/警告包装成 ModuleDependencyErrorModuleDependencyWarning 并存入 this.errorsthis.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();
	}
相关推荐
careybobo28 分钟前
海康摄像头通过Web插件进行预览播放和控制
前端
杉之2 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
喝拿铁写前端2 小时前
字段聚类,到底有什么用?——从系统混乱到结构认知的第一步
前端
再学一点就睡2 小时前
大文件上传之切片上传以及开发全流程之前端篇
前端·javascript
木木黄木木3 小时前
html5炫酷图片悬停效果实现详解
前端·html·html5
请来次降维打击!!!4 小时前
优选算法系列(5.位运算)
java·前端·c++·算法
難釋懷4 小时前
JavaScript基础-移动端常见特效
开发语言·前端·javascript
自动花钱机5 小时前
WebUI问题总结
前端·javascript·bootstrap·css3·html5
拉不动的猪5 小时前
简单回顾下pc端与mobile端的适配问题
前端·javascript·面试
拉不动的猪5 小时前
刷刷题49(react中几个常见的性能优化问题)
前端·react.js·面试