webpack JS meta 信息插件 /lib/JavascriptMetaInfoPlugin.js

  • 插件名称定义为 JavascriptMetaInfoPlugin,并应用于 Webpack 的编译流程中。

  • 监听 compiler.hooks.compilation 钩子,在编译过程中注入逻辑。

  • 为三种 JavaScript 模块类型(AUTO、DYNAMIC、ESM)注册 parser 钩子,统一处理逻辑。

  • 在解析阶段监听 eval() 的调用:

    • 标记 buildInfo.moduleConcatenationBailout = "eval()",阻止模块作用域连接优化。
    • 设置 buildInfo.usingEval = true,记录模块使用了 eval()。
    • 使用 InnerGraph.getTopLevelSymbol() 尝试获取当前上下文的顶层符号。
    • 如果存在顶层符号,则调用 InnerGraph.addUsage() 记录引用关系。
    • 否则调用 InnerGraph.bailout(),中断内部图优化。
  • 在解析结束时(parser.finish)记录顶层变量声明:

    • 初始化 buildInfo.topLevelDeclarations 为一个 Set。
    • 遍历作用域中定义的变量名。
    • 如果变量没有自由变量信息(非闭包变量),视为顶层声明加入集合。
  • 最终导出插件类用于 Webpack 插件系统使用。

js 复制代码
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Sergey Melyukov @smelukov
*/
// 这是插件的许可证信息和作者署名

"use strict";
// 启用严格模式,提高代码的规范性和安全性

const {
	JAVASCRIPT_MODULE_TYPE_AUTO,
	JAVASCRIPT_MODULE_TYPE_DYNAMIC,
	JAVASCRIPT_MODULE_TYPE_ESM
} = require("./ModuleTypeConstants");
// 引入三种 JavaScript 模块类型常量:自动识别、动态模块、ES 模块

const InnerGraph = require("./optimize/InnerGraph");
// 引入 InnerGraph,用于分析模块的内部依赖关系图(变量引用、作用域等)

/** @typedef {import("./Compiler")} Compiler */
// 引入类型定义:Compiler

/** @typedef {import("./Module").BuildInfo} BuildInfo */
// 引入类型定义:模块的构建信息 BuildInfo

/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
// 引入类型定义:JavaScript 语法解析器 JavascriptParser

const PLUGIN_NAME = "JavascriptMetaInfoPlugin";
// 定义插件名称常量,后续钩子绑定中使用

class JavascriptMetaInfoPlugin {
	/**
	 * 插件应用函数
	 * @param {Compiler} compiler 编译器实例
	 * @returns {void}
	 */
	apply(compiler) {
		// 在 compilation 阶段注册钩子
		compiler.hooks.compilation.tap(
			PLUGIN_NAME,
			(compilation, { normalModuleFactory }) => {
				/**
				 * 处理 JavaScript 解析器的钩子函数
				 * @param {JavascriptParser} parser 解析器实例
				 * @returns {void}
				 */
				const handler = parser => {
					// 为 eval() 函数调用绑定钩子
					parser.hooks.call.for("eval").tap(PLUGIN_NAME, () => {
						const buildInfo =
							/** @type {BuildInfo} */
							(parser.state.module.buildInfo);
						// 使用 eval() 会导致模块无法进行作用域提升优化
						buildInfo.moduleConcatenationBailout = "eval()";
						// 标记当前模块使用了 eval
						buildInfo.usingEval = true;

						// 获取当前作用域的顶层符号
						const currentSymbol = InnerGraph.getTopLevelSymbol(parser.state);
						if (currentSymbol) {
							// 如果获取到了符号,则记录其引用关系
							InnerGraph.addUsage(parser.state, null, currentSymbol);
						} else {
							// 否则标记当前模块无法进行内联图分析(bailout)
							InnerGraph.bailout(parser.state);
						}
					});

					// 在解析完成时记录顶层声明
					parser.hooks.finish.tap(PLUGIN_NAME, () => {
						const buildInfo =
							/** @type {BuildInfo} */
							(parser.state.module.buildInfo);

						let topLevelDeclarations = buildInfo.topLevelDeclarations;
						if (topLevelDeclarations === undefined) {
							// 初始化 topLevelDeclarations 为 Set 集合
							topLevelDeclarations = buildInfo.topLevelDeclarations = new Set();
						}

						// 遍历当前作用域中定义的变量名
						for (const name of parser.scope.definitions.asSet()) {
							const freeInfo = parser.getFreeInfoFromVariable(name);
							// 如果变量没有被视为自由变量,认为它是顶层声明
							if (freeInfo === undefined) {
								topLevelDeclarations.add(name);
							}
						}
					});
				};

				// 为三种 JS 模块类型分别注册 parser 钩子
				normalModuleFactory.hooks.parser
					.for(JAVASCRIPT_MODULE_TYPE_AUTO)
					.tap(PLUGIN_NAME, handler);
				normalModuleFactory.hooks.parser
					.for(JAVASCRIPT_MODULE_TYPE_DYNAMIC)
					.tap(PLUGIN_NAME, handler);
				normalModuleFactory.hooks.parser
					.for(JAVASCRIPT_MODULE_TYPE_ESM)
					.tap(PLUGIN_NAME, handler);
			}
		);
	}
}

module.exports = JavascriptMetaInfoPlugin;
// 导出插件类
相关推荐
计算机魔术师10 分钟前
OpenAI 砍掉 100 亿融资目标,AI 资本市场的温度计变了
前端
jktantan30 分钟前
(二)Vue 3 的 attrs 不是响应式:el-form 扩展属性同步的三种方案
前端·javascript·vue.js·element-plus
前端 贾公子1 小时前
第 5 章:Codex 从可运行程序到可交付工具
java·前端·数据库
用户360055579001 小时前
Kestrel_VLLM - 26 · 发射空档三步曲:事件计时 → nsys → 判别实验
前端
echome8881 小时前
JavaScript async/await 错误处理:别让 Promise 静默失败
开发语言·前端·javascript·promise
PedroQue992 小时前
v0.2.0 架构升级:class + reactive 重塑状态管理
前端·uni-app
鶴哥只手遮天2 小时前
Angular 22 源码级深度解析-第 02 章 编译链路总览:从模板字符串到 `ɵɵ` 指令
前端·开源·angular.js
尘世中一位迷途小书童2 小时前
别再堆万字 Prompt:用 Agent Skills 给团队写一个「前端 Review」Skill
前端·ai编程·cursor
aixingpan2 小时前
aixingpan.cn API开发文档:api_docs_bichart_common2接口指南
前端·php
super_Omni2 小时前
text/PDF/Word → 解析成纯文本 → 分词 → 词表匹配 → 加权打分 → 低于阈值
前端·chrome