Lighthouse 在小程序中的实践 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 小程序相关 >

Lighthouse 在小程序中的实践

发表时间:2021-4-22

发布人:葵宇科技

浏览次数:45

前言

目前哈啰前端应用质量监控使用到了 Lighthouse 作为首页性能问题定性检查的工具,在使用过程中,我们基于 Lighthouse Plugin 对其原有能力进行扩展,用于检测 web 端和小程序的性能问题,在实践中也积累了些经验,希望能通过本文的分享,给大家一些帮助。

Lighthouse 简介

Lighthouse 是一个开源的自动化检测工具,通过内置审计模块,分析 web 应用和 web 页面的性能指标,最终给出页面的首屏得分和最佳实践指南。

使用方式

使用方式有四种,具体可以参考官方使用说明(github.com/GoogleChrom…) ,启动姿势很重要,大家选一款适合自己的。

模块实现

整体架构图如上,模块的实现细节可以参考 Lighthouse 模块实现。 Lighthouse Plugin 主要会涉及到 Gatherers、Audits、Categories 这三个模块。

检测报告

Lighthouse 的检测报告默认展示 5 类信息:

  • Performance(性能)
  • Progressive Web App(渐进式 web 应用)
  • Accessibility(无障碍)
  • Best Practices(最佳实践)
  • SEO(SEO)

可以通过调用不同 config 来展示其中几类。

Lighthouse Plugin 开发入门

可以参考官方文档 ,这里给出一个简单的示例。开发一个plugin,主要分为以下两步:

一、新建 Lighthouse Plugin项目 创建一个 npm 包,包含 plugin.js 和 package.json:

module.exports = {
  // 这里可以新增自己的 audit(审计项)
  audits: [{path: 'lighthouse-plugin-example/test-audit.js'}],
  // 这里可以设置自定义分类的一些信息,比如标题、描述、引用的审计项等
  category: {
    title: 'title',
    description: 'description',
    auditRefs: [{id: 'test-id', weight: 1}],
  },
};
package.json

{
  "name": "lighthouse-plugin-example",
  "main": "plugin.js",
  "peerDependencies": {
    "lighthouse": "^5.6.0"
  },
  "devDependencies": {
    "lighthouse": "^5.6.0"
  }
}
复制代码

注:Lighthouse 要按 peerDependencies 方式引入,避免重复下载。

由于上例用到了新的审计项,所以我们也需要新建这个文件

const { Audit } = require('lighthouse');
class TestAudit extends Audit {
  static get meta() {
    return {
      // 这里定义审计项的一些配置,比如标题、异常描述、依赖的artifacts等
      requiredArtifacts: ['devtoolsLogs'],
    };
  }
  static audit(artifacts) {
    // lighthouse 运行过程会经过一系列的采集器(gatherers),
    // 每个采集器都会收集自己的目标信息,并生成中间产物(artifacts)
    return {
      score: 1,
    };
  }
}
module.exports = TestAudit;
复制代码

二、使用Lighthouse Plugin

如果是命令行,直接运行:

复制代码

如果是 npm 方式运行, Lighthouse 的配置需改为:

  extends: 'lighthouse:default',
  plugins: ['lighthouse-plugin-example'],
  settings: {
    // ...
  },
};
复制代码

Lighthouse Plugin 在项目中的实践

先聊一聊为什么要做 哈啰前端应用质量监控的规划之一,就是统一使用Lighthouse 做多端的首屏性能的定性检查。浏览器端是天然支持的,难点是小程序,无法直接在浏览器中直接运行,也就无法使用 Lighthouse 进行定性检查。所幸,现在有 taro、antmove 等一众的开源工具,可以借助这些工具将小程序转换为运行在浏览器端的应用,如此一来,我们可以将 Lighthouse 集成到我们的工程体系中来,使用相同的工具链对浏览器端和小程序端进行定性检查。

不凭空的制造需求,是商业公司技术团队的立足之本。在整体目标的引导下,我们要考虑如何来检查小程序的性能,传统意义上的Web页面的检查方式是否可以直接搬过来呢?答案是否定的,而对于小程序的技术实现原理,Lighthouse默认那一套不能直接照搬。运行在浏览器端的小程序,FMP、FCI、TTI等都可以做横向对比,但其结果的可靠性还要进行推敲,除此之外,我们需要有一套符合小程序技术特性的分析方法和工具,我们需要开发对应的Lighthouse Plugin,对应的Gatherers、Audits和Categories。

这张截图来自支付宝小程序的部分检测项,在传统 web 端检测的基础上,多了许多小程序特有检测(比如 setData 频率、数据量、API 调用次数、同/异步调用等),这些指标目前 Lighthouse 并非天生就覆盖到。

为小程序定制一个插件

以下以编写一个审计支付宝小程序Native API调用次数的插件为例,简单的总结如下:

业务代码注入采集逻辑 + gatherer 收集采集数据 + audit 消费数据并计算结果

业务代码注入采集逻辑

定义一个日志采集对象window.nativeCall,通过调用window.nativeCall ,通过调用 window.nativeCall.push 采集一次调用行为,示例代码如下。

window.$$nativeCall = {
    calls: [],
  push: function (type, callInfo) {
    this.calls.push({ timestamp: Date.now(), type, callInfo });
  },
};
function $$myproxy(my) {
  return new Proxy(my, {
    get(target, key) {
      const keyValue = https://www.wxapp-union.com/target[key];
      // 如果是API方法,则代理原方法
      if (typeof keyValue ==='function') {
        return $$myProxyFn(keyValue, target, key);
      }
      // 否则,直接上报了一个API属性的调用检测点
            window.$$nativeCall.push('api-attr-called', JSON.stringify({
        key: `my.${key}`,
      }));
      return keyValue;
    }
  });
};
function $$myProxyFn(fn, that, key) {
  return (function (...args) {
    // 上报了一个AP方法的调用检测点,携带自定义参数
    window.$$nativeCall.push('api-method-called', JSON.stringify({
      key: `my.${key}`,
      args,
    }));
    try {
      const result = fn.apply(this, args);
      // 上报了一个AP方法的成功调用的检测点,叫 api-method-success-called
      window.$$nativeCall.push('api-method-success-called', JSON.stringify({
        key: `my.${key}`,
        args,
                result: err,
      }));
    } catch (err) {
      // 上报了一个AP方法的异常调用检测点,叫 api-method-error-called
      window.$$nativeCall.push('api-method-error-called', JSON.stringify({
        key: `my.${key}`,
        args,
                result: err,
      }));
    }
  }).bind(that);
}
复制代码

示例代码写的比较简单,只是将调用信息存储在了window.$$nativeCall中。这段代码需要通过编译工具链来插入到小程序的业务代码中,以拦截小程序代码中所有的Native API的调用。

自定义 audit 审计模块

在进行审计分析之前,我们需要一个 Gatherer 来获取window.$$nativeCall采集到的信息。

const { Gatherer } = require('lighthouse');
class CustomNativeCall extends Gatherer {
  public async afterPass(passContext) {
    const { driver } = passContext;
    const $$nativeCall = await driver.evaluateAsync('window.$$nativeCall');
    if ($$nativeCall) {
      return $$nativeCall.calls;
    }
    return [];
  }
}
module.exports = CustomNativeCall;
复制代码

收集器写好了。我们需要编写 Audit 的处理逻辑,这里,我们以统计 Native API 调用次数(api-method-called)为例:

const { Audit } = require('lighthouse');
class ApiMethodCalledAudit extends Audit {
  static get meta() {
    return {
     // 定义好 id,这样 plugin.js 就能找到这个审计项
     id: 'api-method',
     // 这里引入上面定义好的收集器
     requiredArtifacts: ['CustomNativeCall'],
    };
  }
  static audit(artifacts) {
    const { CustomNativeCall } = artifacts;
    const apiMap = {};
    CustomNativeCall.forEach((log) => {
     const {
       // timestamp, // 时间戳在这个审计项中没用到,可以不声明
       type,
       callInfo,
     } = log;
      // 判断type是否是我们上报的特定类型:api-method-called
      if (type === 'api-method-called') {
        const { key } = JSON.parse(callInfo);
        // 取出api的方法名,计数
        apiMap[key] = apiMap[key] || 0;
        apiMap[key] += 1;
      }
    });
    const result = Object.keys(apiMap).reduce((res, apiKey) => {
      res.push({
        api: apiKey,
        count: apiMap[apiKey],
      });
      return res;
    }, []);
    return {
      // 生成表格明细
      details: Audit.makeTableDetails(ApiMethodCalledAudit.getHeadings(), result),
      // 结果展示文案
      displayValue: `共找到 ${result.length} 次API方法调用`,
      // 评分,区间在0-1,1表示该审计项满分
      score: 1,
    };
  }
  
  private static getHeadings() {
    return [
      {
        itemType: 'text',
        key: 'api',
        text: '名称',
      },
      {
        itemType: 'numeric',
        key: 'count',
        text: '调用次数',
      },
    ];
  }
};
module.exports = ApiMethodCalledAudit;
复制代码

最后,在我们的 plugin.js 引入 api-method-called-audit.js

module.exports = {
  audits: [{path: 'lighthouse-plugin-example/api-method-called-audit.js'}],
  category: {
    title: '容器',
    description: 'description',
    // 这里注入plugin用到的audit依赖,id取自audit里的meta.id
    auditRefs: [{id: 'api-method', weight: 1}],
  },
};
复制代码

至此,数据上报、采集、消费整个流程便打通了。

小程序中的实践总结 以下整理了当前我们实际项目中定义的部分日志类型、审计模块。

日志类型

  • api-attr-called:用于 API 属性访问次的相关统计
  • api-method-error-called:用于 API 方法的异常调用次数的统计
  • api-method-called:用于 API 方法的调用次数情况统计
  • api-method-success-called:用于 API 方法的成功调用次数、耗时的统计
  • set-data:用于 setData 调用次数、数据大小的统计
  • set-data-success:用于 setData 调用耗时统计

Audit

  • api-async-same-args-called: 异步 API 方法相同入参调用
  • api-attr-called: API 属性调用
  • api-deprecated-called: 废弃 API 调用
  • api-duplicate-called: API 被重复调用情况(连续 20 次)
  • api-error-called: API 异常调用
  • api-long-time-called: API 调用耗时过长(超过 1000ms)
  • api-method-called: API 方法调用
  • api-sync-called: API 同步方法调用情况
  • page-node-used: 文档节点复杂度
  • set-data-called: setData 调用频繁(20 次/秒)
  • set-data-size: setData 数据量超限(超过 256kb)

Category

我们将审计项分为三大类:

  • performance

主要包含性能相关的审计项,比如setData调用次数、setData单次设置的数据量、页面节点数等等,这些审计项的优化,可以带来相对直观的性能提升。

  • container

主要包含容器相关的审计项,比如小程序api(异常、重复、耗时、相同入参)调用、小程序native属性调用等等,这些审计项和小程序运行环境直接关联。

  • best-practice

主要包含最佳实践相关的审计项,比如图片转webp、禁止废弃api调用、请求异常处理、同步转为异步api调用等等,这些审计项都和官方推荐的开发方式相关。

插件使用方法

以 npm 包方式为例,我们将 Lighthouse 的配置改为:

module.exports = {
  extends: 'lighthouse:default',
  plugins: [
    // 这里引入了容器检测,性能和最佳实践如果需要的话也可以在这里引入
    'lighthouse-plugin-miniprogram/plugins/container'
  ],
  passes: [{
    passName: 'defaultPass',
    gatherers: [
      'lighthouse-plugin-miniprogram/gatherers/custom-native-call',
    ],
  }],
  settings: {
    // ...
  },
};
复制代码

运行结果

这里我们用目前已经写好的统计项作为演示,使用方式和上例一致的。

最后

本文从实际业务出发,简要介绍了 Lighthouse在哈啰前端应用质量监控中的运用,对于如何在小程序中应用好Lighthouse,我们目前也还在探索阶段,欢迎交流。

参考资料

  • Lighthouse-developers(文章链接:developers.google.com/web/tools/l…
  • Lighthouse 测试内幕(文章链接:juejin.im/post/5dca05…
  • Web 性能优化地图(文章链接:github.com/berwin/Blog…
  • Chrome DevTools Protocol(文章链接:chromedevtools.github.io/devtools-pr…
  • Lighthouse-architecture(文章链接:github.com/GoogleChrom…

相关案例查看更多