webpack 格式化模块 第 一 节

这段代码主要是为 Webpack 中的 NormalModule 模块构建逻辑 提供一系列:

  1. 类型定义(Type Definitions) :包括 SourceMapLoaderItemNormalModuleCreateDataCompilationHooks 等。
  2. 工具函数(Utility Functions) :如 contextifySourceUrlcontextifySourceMapasBufferasString 等,用于处理路径、SourceMap 格式、数据转换。
  3. 错误处理(Error Wrapping) :定义了 NonErrorEmittedError,用于处理非标准错误对象。
  4. Hook 管理(Hook Registration) :通过 compilationHooksMap 存储和隔离每个编译任务的钩子集合。

🔧 总体上,这是 Webpack 中 NormalModule 的 底层构建机制 的一部分,它服务于模块的读取、加载、解析、缓存、source map 注入、错误处理和生命周期钩子等操作。

js 复制代码
/**
 * 类型定义:引入 FakeHook 类型,用于替代真实的 Tapable Hook。
 * 通常用于过时的 hook 的兼容处理。
 */
 /**
 * @template T
 * @typedef {import("./util/deprecation").FakeHook<T>} FakeHook
 */

/**
 * 类型定义:解析器(parser)和生成器(generator)所使用的参数类型。
 * 实际上是任意键值对对象。
 */
 /** @typedef {{[k: string]: any}} ParserOptions */
 /** @typedef {{[k: string]: any}} GeneratorOptions */

/**
 * 类型定义:NormalModule 在缓存中存储的结构,包括 parser、generator 及其 options。
 */
 /** @typedef {UnsafeCacheData & { parser: undefined | Parser, parserOptions: undefined | ParserOptions, generator: undefined | Generator, generatorOptions: undefined | GeneratorOptions }} NormalModuleUnsafeCacheData */

 /**
  * 类型定义:Loader 上下文,传递给每个 Loader 的 `this` 对象。
  */
 /** @template T
  * @typedef {import("../declarations/LoaderContext").LoaderContext<T>} LoaderContext
  */

 /** @template T
  * @typedef {import("../declarations/LoaderContext").NormalModuleLoaderContext<T>} NormalModuleLoaderContext
  */

 /**
  * SourceMap 的结构定义,描述打包后的代码如何映射到源代码。
  */
 /** @typedef {object} SourceMap
  * @property {number} version Source Map 版本
  * @property {string[]} sources 原始源文件路径
  * @property {string} mappings 映射数据
  * @property {string=} file 生成的文件名
  * @property {string=} sourceRoot 可选源文件根路径
  * @property {string[]=} sourcesContent 原始源代码内容
  * @property {string[]=} names 所有涉及到的变量名
  * @property {string=} debugId 调试用的 ID
  */

 // 懒加载模块并进行缓存,避免重复 require。
const getInvalidDependenciesModuleWarning = memoize(() =>
	require("./InvalidDependenciesModuleWarning")
);
const getValidate = memoize(() => require("schema-utils").validate);

// 判断是否为绝对路径的正则表达式。
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:\\|\\\\|\/)/;

/**
 * 类型定义:代表一个 loader 项,包含其路径、选项、标识符等。
 */
 /** @typedef {object} LoaderItem
  * @property {string} loader loader 路径
  * @property {any} options 配置参数
  * @property {string?} ident 可选标识符
  * @property {string?} type 可选 loader 类型
  */

 /**
  * 将源文件路径转换为 `webpack://` 协议开头的路径,供 SourceMap 使用。
  */
 const contextifySourceUrl = (context, source, associatedObjectForCache) => {
	if (source.startsWith("webpack://")) return source;
	return `webpack://${makePathsRelative(context, source, associatedObjectForCache)}`;
};

/**
 * 替换 SourceMap 中所有 source 的路径为 `webpack://` 协议,便于调试。
 */
 const contextifySourceMap = (context, sourceMap, associatedObjectForCache) => {
	if (!Array.isArray(sourceMap.sources)) return sourceMap;

	const { sourceRoot } = sourceMap;
	const mapper = !sourceRoot
		? source => source
		: sourceRoot.endsWith("/")
			? source =>
					source.startsWith("/")
						? `${sourceRoot.slice(0, -1)}${source}`
						: `${sourceRoot}${source}`
			: source =>
					source.startsWith("/")
						? `${sourceRoot}${source}`
						: `${sourceRoot}/${source}`;

	const newSources = sourceMap.sources.map(source =>
		contextifySourceUrl(context, mapper(source), associatedObjectForCache)
	);
	return {
		...sourceMap,
		file: "x",
		sourceRoot: undefined,
		sources: newSources
	};
};

/**
 * 将 Buffer 类型转为 UTF-8 字符串,反之亦然。
 */
 const asString = input => {
	if (Buffer.isBuffer(input)) {
		return input.toString("utf-8");
	}
	return input;
};
/**
 * 将字符串转换为 buffer utf-8
 */

const asBuffer = input => {
	if (!Buffer.isBuffer(input)) {
		return Buffer.from(input, "utf-8");
	}
	return input;
};

/**
 * 自定义 Webpack 错误类型:用于处理不是 Error 实例但被 emit 出来的错误。
 */
 class NonErrorEmittedError extends WebpackError {
	constructor(error) {
		super();
		this.name = "NonErrorEmittedError";
		this.message = `(Emitted value instead of an instance of Error) ${error}`;
	}
}

// 支持序列化该错误类型
makeSerializable(
	NonErrorEmittedError,
	"webpack/lib/NormalModule",
	"NonErrorEmittedError"
);

/**
 * NormalModule 编译过程中会触发的一系列钩子(生命周期钩子)
 */
 /** @typedef {object} NormalModuleCompilationHooks
  * @property {SyncHook<[LoaderContext<any>, NormalModule]>} loader 执行 loader 前调用
  * @property {SyncHook<[LoaderItem[], NormalModule, LoaderContext<any>]>} beforeLoaders 加载 loaders 前调用
  * @property {SyncHook<[NormalModule]>} beforeParse 解析前调用
  * @property {SyncHook<[NormalModule]>} beforeSnapshot 生成文件快照前调用
  * @property {HookMap<FakeHook<AsyncSeriesBailHook<[string, NormalModule], string | Buffer | null>>>} readResourceForScheme 基于 URL 协议读取资源
  * @property {HookMap<AsyncSeriesBailHook<[LoaderContext<any>], string | Buffer | null>>} readResource 读取模块资源
  * @property {AsyncSeriesBailHook<[NormalModule, NeedBuildContext], boolean>} needBuild 判断模块是否需要重新构建
  */

/**
 * 创建 NormalModule 实例所需的数据结构。
 */
 /** @typedef {object} NormalModuleCreateData
  * @property {string=} layer 模块所属的构建层(可选)
  * @property {JavaScriptModuleTypes | ""} type 模块类型(如 commonjs、esm)
  * @property {string} request 解析后的请求路径(含 loader)
  * @property {string} userRequest 用户原始请求(不含 loader)
  * @property {string} rawRequest 原始请求(未解析)
  * @property {LoaderItem[]} loaders 模块使用的 loader 列表
  * @property {string} resource 最终资源的路径
  * @property {Record<string, any>=} resourceResolveData 资源解析信息
  * @property {string} context 上下文路径
  * @property {string=} matchResource 虚拟资源路径(可选)
  * @property {Parser} parser 模块使用的解析器
  * @property {ParserOptions=} parserOptions 解析器配置
  * @property {Generator} generator 代码生成器
  * @property {GeneratorOptions=} generatorOptions 生成器配置
  * @property {ResolveOptions=} resolveOptions 模块解析相关配置
  */

 /**
  * WeakMap 结构用于为每一个 Compilation 存储独立的 NormalModule 钩子,避免污染 Compilation 实例。
  */
const compilationHooksMap = new WeakMap();
相关推荐
咖啡虫几秒前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
拉不动的猪20 分钟前
设计模式之------策略模式
前端·javascript·面试
旭久21 分钟前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js
独行soc31 分钟前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
uhakadotcom1 小时前
Google Earth Engine 机器学习入门:基础知识与实用示例详解
前端·javascript·面试
麓殇⊙1 小时前
Vue--组件练习案例
前端·javascript·vue.js
outstanding木槿1 小时前
React中 点击事件写法 的注意(this、箭头函数)
前端·javascript·react.js
会点php的前端小渣渣1 小时前
vue的计算属性computed的原理和监听属性watch的原理(新)
前端·javascript·vue.js
_一条咸鱼_2 小时前
深入解析 Vue API 模块原理:从基础到源码的全方位探究(八)
前端·javascript·面试
患得患失9492 小时前
【前端】【难点】前端富文本开发的核心难点总结与思路优化
前端·富文本