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;
}
相关推荐
rechol1 小时前
类与对象(中)笔记整理
java·javascript·笔记
Luffe船长1 小时前
前端vue2+js+springboot实现excle导入优化
前端·javascript·spring boot
Demoncode_y1 小时前
前端布局入门:flex、grid 及其他常用布局
前端·css·布局·flex·grid
明天最后1 小时前
使用 Service Worker 限制请求并发数
前端·service worker
仲夏幻境2 小时前
js利用ajax同步调用如何
开发语言·javascript·ajax
java水泥工2 小时前
基于Echarts+HTML5可视化数据大屏展示-电信厅店营业效能分析
前端·echarts·html5·大屏展示
鹿鹿鹿鹿isNotDefined2 小时前
Pixelium Design:Vue3 的像素风 UI 组件库
前端·javascript·vue.js
运维行者2 小时前
知乎崩了?立即把网站监控起来!
前端·javascript·后端
stayong2 小时前
市面主流跨端开发框架对比
前端
一米八二的矮个子2 小时前
JavaScript语法进阶(一)
javascript