rollup 插件架构-装饰器模式增添插件性能分析

文章目录

输入 rollup 配置

  • 初始化计时器,构建完成时输出每个阶段的耗时、内存占用等信息,会 wrapper 相应 hook 方法,添加计时相关功能
java 复制代码
initialiseTimers(inputOptions); 

根据用户配置开启插件性能分析

javascript 复制代码
export function initialiseTimers(inputOptions: NormalizedInputOptions): void {
	if (inputOptions.perf) { // 开启插件性能分析
		timers = new Map();
		timeStart = timeStartImpl;
		timeEnd = timeEndImpl;
		inputOptions.plugins = inputOptions.plugins!.map(getPluginWithTimers);
	} else {
		timeStart = NOOP;
		timeEnd = NOOP;
	}
}

性能分析函数实现

  • 通过 node 相关 Api 获取堆栈信息,process.memoryUsage()
javascript 复制代码
let timers = new Map<string, Timer>();

// 记录开始
function timeStartImpl(label: string, level = 3): void {
	label = getPersistedLabel(label, level);

	const startMemory = process.memoryUsage().heapUsed;
	const startTime = performance.now();

	const timer = timers.get(label);

	if (timer === undefined) { // 初始化创建对应标签
		timers.set(label, {
			memory: 0,
			startMemory,
			startTime,
			time: 0,
			totalMemory: 0
		});
	} else {
		timer.startMemory = startMemory;
		timer.startTime = startTime;
	}
}

// 记录结束
function timeEndImpl(label: string, level = 3): void {
	label = getPersistedLabel(label, level);

	const timer = timers.get(label);

	if (timer !== undefined) {
		const currentMemory = process.memoryUsage().heapUsed;
		timer.memory += currentMemory - timer.startMemory;
		timer.time += performance.now() - timer.startTime;
		timer.totalMemory = Math.max(timer.totalMemory, currentMemory);
	}
}

分级输出结果

  • 根据 level 控制台输出对应格式信息
javascript 复制代码
function getPersistedLabel(label: string, level: number): string {
	switch (level) {
		case 1: {
			return `# ${label}`;
		}
		case 2: {
			return `## ${label}`;
		}
		case 3: {
			return label;
		}
		default: {
			return `${'  '.repeat(level - 4)}- ${label}`;
		}
	}
}

装饰器模式拓展组件

  • 枚举需要性能分析的插件 hookName ,添加timeStart、timeEnd 分析功能
javascript 复制代码
export function initialiseTimers(inputOptions: NormalizedInputOptions): void {
	if (inputOptions.perf) { // 是否开启性能分析
		timers = new Map();
		timeStart = timeStartImpl; // 记录开始
		timeEnd = timeEndImpl; // 记录结束
		inputOptions.plugins = inputOptions.plugins!.map(getPluginWithTimers);
	} else {
		timeStart = NOOP;
		timeEnd = NOOP;
	}
}
javascript 复制代码
const TIMED_PLUGIN_HOOKS: readonly (keyof PluginHooks)[] = [
	'augmentChunkHash',
	'buildEnd',
	'buildStart',
	'...',
	'writeBundle'
];

function getPluginWithTimers(plugin: any, index: number): Plugin {
	// 遍历需要分析的组件
	for (const hook of TIMED_PLUGIN_HOOKS) {
		if (hook in plugin) {
			let timerLabel = `plugin ${index}`;
			if (plugin.name) {
				timerLabel += ` (${plugin.name})`;
			}
			timerLabel += ` - ${hook}`; // 设置对应标签名
			
			// 在调用原插件方法前后增加性能分析
			const handler = function (this: any, ...parameters: readonly unknown[]) {
				timeStart(timerLabel, 4);
				const result = hookFunction.apply(this, parameters);
				timeEnd(timerLabel, 4);
				return result;
			};

			let hookFunction: any;
			
			// 格式化插件配置
			if (typeof plugin[hook].handler === 'function') {
				hookFunction = plugin[hook].handler;
				plugin[hook].handler = handler;
			} else {
				hookFunction = plugin[hook];
				plugin[hook] = handler;
			}
		}
	}
	return plugin;
}
相关推荐
彩票管理中心秘书长26 分钟前
一次搞懂:在Vue里用Showdown渲染Markdown+KaTeX数学公式
前端
m0_7381207231 分钟前
应急响应(重点)——记一次某公司流量应急溯源分析(附带下载链接)
服务器·前端·数据库·安全·web安全·网络安全
前端Hardy1 小时前
pnpm 11.0 正式登场:安装起飞、安全拉满、彻底告别 npm 依赖
前端
PILIPALAPENG1 小时前
第4周 Day 1:智能体记忆系统——给 Agent 一个"大脑"
前端·人工智能·python
_风满楼1 小时前
TDD实战-会议室冲突检测的红绿重构循环
前端·javascript·算法
Rkgua1 小时前
JS中的惰性函数基本介绍
前端·javascript
客场消音器1 小时前
我用两周半 Vibe Coding 做了一个前额叶训练的微信小程序
前端·javascript·后端
铁皮饭盒2 小时前
成为AI全栈 - 第4课:Drizzle ORM SQLite Elysia 数据库实战
前端·后端
ascarl20102 小时前
Linux.do 帖子整理:AI 调用 Chrome DevTools 调试前端页面
linux·前端·人工智能
DanCheOo2 小时前
开源 | 我是怎么用 ai-memory 让 Cursor 每次开新对话都自动知道项目背景的
前端·人工智能·ai·ai编程