性能分析工具能够有效地帮助你找出那些导致系统运行缓慢的问题。例如,它们可以告诉你“最大内容绘制时间”为4.2秒,或者你的JavaScript代码文件体积过大,又或者某些图片在页面滚动到该位置之前就已经开始加载了。

但是,这些工具通常无法提供作为开发者所需要的重要信息:我应该让我的编程辅助工具去修改哪些内容呢?

AI编程辅助工具确实可以帮助你解决性能问题,但它们需要明确的指令和相关的背景信息。如果你只是简单地说“让这个网站运行得更快一些”,那么得到的建议往往会比较笼统;而如果你向这些工具提供具体的指标、受影响的资源、可能的原因以及需要优先检查的文件,那么获得有用的修改建议的概率就会大大提高。

在本教程中,你将学习如何将浏览器性能分析的结果转化为结构化明确的指令,以便让编程辅助工具能够根据这些指令进行相应的修改。同时,你还会了解到如何为Chrome DevTools扩展程序添加一个“复制AI修改提示”的按钮。

我会以我开发的Chrome DevTools扩展程序PerfLens作为示例来进行讲解。不过,这种方法其实适用于任何能够收集性能数据的工具。

你将构建什么

最终,你会构建出一个如下所示的小型工作流程:

性能分析结果 → 结构化问题描述 → AI修改提示 → 复制到剪贴板 → 编程辅助工具 → 代码修改 → 重新运行性能检测

完成这个过程后,你将会拥有以下功能:

  • 用于存储性能分析结果的数据结构

  • 用于生成结构化修改提示的函数

  • 用于将修改提示复制到剪贴板的功能

  • 一个能够将生成的提示复制到DevTools面板中的按钮

  • 一种简单的方法,用于验证修改是否有效

先决条件

要跟随本教程进行学习,你需要具备以下基础知识:

  • 基础的JavaScript或TypeScript编程知识

  • 对浏览器扩展程序的基本概念有了解

  • 大致了解Chrome DevTools面板的工作原理

  • 会使用诸如Cursor、Claude Code、GitHub Copilot之类的AI编程辅助工具

  • 在本教程中,你并不需要构建一个完整的性能审计系统。我们的重点在于学习如何将性能分析工具的结果传递给编程辅助工具进行处理。

    目录

    为什么性能报告难以转化为代码修改

    性能评分只是一种表现结果。例如,某份报告可能会显示如下内容:

    最大内容绘制时间:4.2秒

    这个数字确实很重要,但它并不能告诉你问题出在哪个地方,以及应该如何进行修复。

    造成性能问题的原因可能包括:

    • 图片文件过大

    • 某些脚本会阻塞页面渲染

    • 首页加载的JavaScript代码过多

    • API请求速度过慢

    • 图片尺寸信息缺失,导致布局紊乱

    作为开发人员,你通常需要将这份报告转化为具体的代码修改任务。

    这个转化过程需要花费时间。不过,如果你为辅助工具提供足够的背景信息,它就能发挥很大的作用。

    与其要求辅助工具“让网站运行得更快”,不如给出更明确的指令:

    首页上有一张大小为258.1 KB的图片,这影响了页面加载速度。请先检查首页的标题区域及相关图片组件。调整图片的大小或压缩它,但不要改变页面布局。同时,请说明如何验证修改效果。

    这样的指令更容易让辅助工具执行操作,因为它指明了具体的问题所在。

    一个好的AI修复提示应该包含哪些内容

    一个优秀的AI修复提示应该类似于一份简短的工程任务说明。

    它应该包括以下信息:

    • 存在的性能问题

    • 用于证明问题的数据或证据

    • 受到影响的页面或资源

    • 可能的原因

    • 首先需要检查的文件或代码部分

    • 推荐的修复方案

    • 修改过程中需要注意的限制条件

    • 验证修改效果的方法

    以下是一个示例提示:

    你正在帮助优化一个处于生产环境中的Next.js应用程序。
    
    问题:页面上有一张大小为258.1 KB的图片,这可能会影响页面加载速度。
    证据:图片文件大小为258.1 KB
    受影响的页面地址:http://localhost:3000
    需要检查的资源文件路径:http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&w=3840&q=75
    
    可能的原因:
    该页面加载的图片尺寸超出了实际显示所需的大小。
    
    首先请检查以下文件或代码部分:
    - `app/page.tsx` 或 `pages/index.tsx`
    - `components/**/*.{tsx,jsx}`
    - `next.config.js`
    - 页面标题区域及相关图片组件
    
    推荐的修复方案:
    调整图片的大小或压缩它,使用现代格式的图片文件,并明确指定图片的宽高值,以确保页面布局不会受到影响。
    
    需要注意的限制条件:
    - 仅对导致问题的具体路由或组件进行修改。
    - 除非没有其他合理的替代方案,否则不要添加新的依赖项。
    - 在应用任何修改之前,请先解释其目的。
    
    修改完成后,请执行以下操作:
    - 重新运行性能检测。
    - 确认图片文件的传输大小是否有所减少。
    - 检查页面布局是否仍然正常。

    这个提示非常具体,它清楚地说明了问题所在、需要检查的位置、应该进行的修改内容,以及如何验证修改效果。

    这就是AI问题报告的核心理念所在。

    在PerfLens中,性能问题的记录方式就是这样的:每一个检测结果都会被转化为一个AI问题报告,其中会包含测量得到的数值、受影响的资源以及相应的处理建议。而“复制AI处理建议”按钮则能让你一键将整个报告传递给负责编码的团队成员。

    PerfLens截图

    如何将性能问题记录为结构化数据

    在生成处理建议之前,首先需要将这些性能问题以数据的形式保存下来。

    以下是一个简单的TypeScript类型定义:

    type Finding = {
      id: string;
      title: string;
      metric: string;
      measured: string;
      budget?: string;
      resource?: string;
      likelyCause: string;
      recommendedFix: string;
      inspectFirst: string[];
      severity: "low" | "medium" | "high";
    };
    

    每个字段都有其特定的用途:

    • id用于标识问题的类型。

    • title用于提供人类可读的摘要描述。

    • metric用于命名所测量的指标。

    • measured用于存储实际测量得到的数值。

    • budget用于记录目标值(如果有的话)。

    • resource用于标识受到影响的资源文件或URL地址。

    • likelyCause用于说明问题出现的原因。

    • recommendedFix

      为处理团队提供具体的操作方向。

    • inspectFirst用于提示团队优先检查哪些文件。

    • severity

      有助于决定先展示哪些信息。

    以下是一个关于图片尺寸过大的示例:

    const finding: Finding = {
      id: "image-weight",
      title: "图片大小为258.1 KB,可能会导致页面加载速度变慢",
      metric: "Image size",
      measured: "258.1 KB",
      resource: "http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&w=3840&q=75",
      likelyCause:
        "页面加载的图片尺寸超出了实际显示所需的大小。",
      recommendedFix:
        "调整图片大小或对其进行压缩,使用现代格式,并明确指定图片的宽度和高度。",
      inspectFirst: [
        "app/page.tsx or pages/index.tsx",
        "components/**/*.{tsx,jsx}",
        "next.config.js",
        "the hero section or image component",
      ],
      severity: "high",
    };
    

    在这个阶段,你还没有使用AI技术来处理这些数据,只是将性能检测的结果转化成了一个结构化对象而已。

    这个对象为后续生成处理建议提供了可靠的基础。

    如何选择最重要的问题进行处理

    你应该避免一次性向助手提交十个无关的性能问题。

    如果提交的提示信息中包含太多问题,那么生成的修复方案也会非常复杂,这样审核结果就会变得困难。

    更好的做法是针对每个发现的问题分别生成一条提示信息。

    你可以先使用一个简单的严重性评分机制来进行评估:

    function scoreFinding(finding: Finding): number {
      const severityWeight = {
        low: 1,
        medium: 2,
        high: 3,
      };
    
      return severityWeight[finding.severity];
    }
    

    之后,你可以根据评分结果对这些问题进行排序:

    function sortFindings(findings: Finding[]): Finding[] {
      return [...findings].sort(
        (a, b) => scoreFinding(b) - scoreFinding(a)
      );
    }
    

    这个版本虽然简单,但已经足够用来开始使用了。

    日后,你还可以通过考虑以下因素来进一步完善评分机制:

    • 该问题的严重程度超出了预算范围的多少

    • 这个问题是否会影响“最大内容绘制时间”这一指标

    • 这个问题是否会导致布局变化或交互延迟

    • 受影响的资源是否属于页面的首次加载内容

    • 你对所推荐的修复方案有多大的信心

    我们的目标并不是创建一个完美的评分系统,而是帮助你一次专注于解决一个具有高影响力的问题。

    如何构建AI修复提示信息

    一旦你获得了某个Finding对象,构建相应的提示信息就变成了一个字符串格式化的工作。

    此外,你还需要一些关于页面的上下文信息:

    type PageContext = {
      framework: string;
      mode: string;
      pageUrl: string;
    };
    

    页面上下文信息包括:该问题所出自的页面所使用的开发框架、当前是处于开发环境还是生产环境,以及被审核的具体URL地址。

    Finding对象会告诉助手“什么地方”存在性能问题,而页面上下文信息则会说明修复操作应该在“哪里”进行,以及代码的实现方式是如何样的。这些信息非常重要,因为同样的问题在不同的技术环境中可能需要采用不同的解决方法。例如,在Next.js中,处理过大尺寸图片通常需要通过next/imagenext.config.js文件来实现,而在其他开发框架中则可能采用其他的解决方案。mode字段还可以提示我们是否应该已经应用了生产环境的优化措施。

    如果提前向助手提供这些信息,它就可以减少猜测你的开发环境设置所需的时间,从而把更多精力集中在实际的修复工作上。

    接下来,你可以创建一个用于生成修复提示信息的函数:

    function buildFixPrompt(finding: Finding, ctx: PageContext): string {
      const lines = [
        "你正在帮助优化一个使用" + ctx.framework + "框架、处于" + ctx.mode + "构建模式的应用程序。",
        "",
        "问题:" + finding.title,
        "证据:" + finding.metric + " = " + finding.measured +
          (finding.budget ? " (预算为:” + finding.budget + ")" : ""),
        "页面地址:" + ctx.pageUrl,
      ];
    
      if (finding.resource) {
        lines.push("受影响的资源是:" + findingresource);
      }
    
      lines.push(
        "",
        "可能的原因:

    finding.likelyCause, "", "首先检查:

    ...finding.inspectFirst.map((file) => "- " + file), "", "推荐的修复方案:

    finding.recommendedFix, "", "注意事项:

    "- 请确保所做的修改仅限于导致性能问题的那个路由或组件。", "- 除非没有其他合理的替代方案,否则不要添加新的依赖项。", "- 在应用任何修改之前,请先解释其目的。", "", "修改后的操作:

    "- 重新运行性能审计测试。", "- 确认问题确实得到了解决。", "- 检查用户界面是否仍然能够正常使用。", ); return lines.join("\n"); }

    你可以这样调用它:

    const pageContext: PageContext = {
      framework: "Next.js",
      mode: "production",
      pageUrl: "http://localhost:3000",
    };
    
    const prompt = buildFixPrompt(finding, pageContext);
    

    输出的结果是一个你可以复制到编码工具中的提示信息。

    framework字段特别有用。如果编码工具知道该应用使用了Next.js,它就可以查找诸如app/page.tsxpages/index.tsxnext.config.js这些文件,以及通过next/image使用的图片资源。

    如何将提示信息复制到剪贴板

    最安全的集成方式就是先将提示信息复制到剪贴板中。

    许多编码工具和编辑器都支持不同的启动方式。有些支持深度链接,有些在终端中运行,还有一些直接集成在编辑器内部。但所有的这些工具都能够接受从剪贴板中粘贴过来的文本。

    下面是一个简单的复制函数:

    async function copyPrompt(prompt: string): Promise<void> {
      await navigator.clipboard.writeText(prompt);
    }
    

    在浏览器扩展程序的用户界面中,你可以通过点击按钮等操作来调用这个函数:

    copyButton.addEventListener("click", async () => {
      const prompt = buildFixPrompt(finding, pageContext);
    
      await copyPrompt(prompt);
    
      copyButton.textContent = "提示信息已复制";
    });
    

    在复制提示信息后,你也可以尝试打开某个编辑器来使用这些信息:

    type AgentTarget = "cursor" | "vscode" | "copy-only";
    
    async function sendToAgent(
      prompt: string,
      target: AgentTarget
    ): Promise<void> {
      await navigator.clipboard.writeText(prompt);
    
      if (target === "cursor") {
        window.location.href = "cursor://";
        return;
      }
    
      if (target === "vscode") {
        window.location.href = "vscode://";
        return;
      }
    }
    

    这个函数并不会自动将提示信息粘贴到指定的工具中,它只是复制提示信息,然后尝试打开用户选择的工具。

    这种设计其实很有用,因为它能让工作流程更加有序,让你在发送提示信息之前有时间先仔细查看它。

    如何将按钮添加到DevTools面板中

    如果你将这个功能集成到Chrome扩展程序中,就可以让它显示在DevTools面板里。

    首先,在你的manifest.json文件中注册一个DevTools页面:

    {
      "manifest_version": 3,
      "name": "PerfLens",
      "version": "1.0.0",
      "devtools_page": "devtools.html",
      "permissions": ["clipboardWrite", "activeTab", "scripting"]
    }
    

    然后,通过你的DevTools脚本来创建这个面板:

    chrome.devtools.panels.create(
      "PerfLens",
      "icons/icon-32.png",
      "panel.html"
    );
    

    在面板内部,为每一个检测结果都添加一个按钮。

    function renderFinding(
      finding: Finding,
      ctx: PageContext
    ): HTMLElement {
      const item = document.createElement("article");
      const title = document.createElement("h3");
      const button = document.createElement("button");
    
      title.textContent = finding.title;
      button.textContent = "复制AI修复提示";
    
      button.addEventListener("click", async () => {
        const prompt = buildFixPrompt(finding, ctx);
    
        await sendToAgent(prompt, "copy-only");
    
        button.textContent = "提示已复制";
      });
    
      item.append(title, button);
    
      return item;
    }
    

    关键部分在于按钮处理程序。

    当你点击该按钮时,你的扩展程序会执行以下操作:

    1. 根据性能分析结果生成提示信息。

    2. 将这条提示信息复制到剪贴板中。

    3. 显示提示信息已成功复制的反馈信息。

    之后你可以将这些提示信息粘贴到代码编辑工具中,从而查看系统推荐的修改方案。

    如何验证修复效果

    只有当指标有所改善时,AI生成的修复建议才具有实际意义。

    在系统提出修改建议后,你应该依次执行以下步骤:

    1. 查看代码差异内容。

    2. 在本地运行应用程序。

    3. 重新加载页面。

    4. 再次进行性能测试。

    5. 将新的测试结果与之前的数据进行对比。

    以图片处理为例,你需要检查以下几点:

    • 图片传输的大小是否有所减少?

    • 图片的清晰度是否仍然足够高?

    • 页面布局是否保持稳定?
    • “最大内容绘制时间”这一指标是否有改善?
    • 这项修改是否影响了其他功能或路径?

    这种处理方式实际上形成了一个简单的循环:

    测试性能 → 生成提示 → 进行代码修改 → 再次测试性能

    你不应该将系统的建议视为最终定论,因为浏览器的实际测量结果才是最权威的依据。

    Lighthouse与这个流程的关系

    Lighthouse仍然非常有用。它能够为你提供详细的性能分析报告以及统一的评分结果。而这个新的工作流程则用于解决不同类型的问题。

    Lighthouse帮助你回答的是:

    在受控环境下,这个页面的表现如何?

    而AI生成的修复建议则能帮助你回答:

    关于隐私问题的说明
    

    AI生成的修复建议中可能会包含URL地址、资源名称、路径信息、文件名以及实现细节等内容。

    在将这些提示信息粘贴到基于云的代码编辑工具之前,请务必检查其中是否包含以下内容:

    • 访问令牌

    • 客户的私人数据

    • 无法共享的内部URL地址

    • 环境变量中的敏感信息

    • 敏感的日志记录

    请确保提示信息仅与性能问题相关,为代码编辑工具提供必要的帮助信息,但不要提供超出其所需范围的细节。

    总结

    通过本教程,你学会了如何将性能分析的结果转化为AI生成的修复建议。

    你掌握了以下方法:

    • Finding类型的结构化数据生成方式
    • 对分析结果进行排序的方法
    • buildFixPrompt函数的实现过程
    • 通过剪贴板将提示信息传递给代码编辑工具的机制
    • 如何在DevTools面板中添加相关按钮
    • 用于验证修复效果的检查流程

    主要思想很简单:性能分析工具能够提供相应的数据,而编程人员则需要这些数据所处的具体环境或背景信息。一个设计良好的AI补丁说明文档就能将这两者紧密地联系起来。

    PerfLens就是这种工作流程的一个示例。如果你想尝试使用这个扩展功能,或者想要了解它是如何实现这一工作流程的,你可以在这里找到相关信息:

Comments are closed.