【前端性能测试】不服?那就跑个分!!!

希沃ENOW大前端javascript

公司官网:CVTE(广州视源股份)html

团队:CVTE旗下将来教育希沃软件平台中心enow团队前端

本文做者:java

小羽名片.png

hello,你们好,我是小羽同窗。一个平凡,而又不甘于平凡的前端开发工程师!git

你们对跑分应该挺熟悉了吧?尤为是米粉,雷老板的那句不服?那就跑个分!应该历历在目吧?哈哈哈程序员

在平常的前端开发过程当中,小伙伴们或多或少都有接触过性能优化吧?可是你日常是怎么肯定性能是否获得了提高呢?Google的开源工具——Lighthouse也就应运而生。github

Lighthouse主要是用于分析网络应用和网页,收集现代性能指标并提供对开发人员最佳实践的意见。对于前端开发工程师来讲,能够简洁明了得看到项目中的不足之处,以及优化的方法。是平常开发中不可多得的神器呀!web

简单的使用

lighthouse 插件安装

chrome的商店中,搜索lighthouse,而后添加。chrome

设置测试项目

而后在chrome顶部的插件栏中打开插件。点击设置图标,还能够选择进行测试(跑分)的项目,以及是测试pc端仍是手机端的网页。npm

测试(跑分)

而后咱们直接点击generate report按钮便可直接进入测试,过一段时间后结果就会出来啦。下面那个图就是咱们ENOW 大前端团队的掘金首页测试评分啦,能够看到掘金seo优化作的仍是很是棒的,哈哈哈~

整个测试报告中给咱们标明了页面中的各类性能相关的参数,而后也给到了咱们不少相关的优化建议。小伙伴们以为感兴趣的话,能够深刻的去了解各个参数哦~

image.png

如今性能测试工具备是有了,可是有没有发现这个就只能一个一个页面的去测,好麻烦呀。若是有几十个页面还得一个一个的去点。大家会不嫌麻烦嘛?反正像小羽同窗这么厌倦重复性工做的人来讲,早就烦死了  (╯°Д°)╯︵┻━┻

如今问题来了,那有没有什么方便的方法呀?一个一个的去点着测试总不是方法呀。

别着急,干货立刻就到啦~

其实除了chrome插件的使用方式,咱们还可使用命令行的方式来调用Lighthouse

1.全局安装 lighthouse

npm install -g lighthouse
复制代码

2.输入你的页面

lighthouse http://test.com
复制代码

小羽在这里就不进行展现了,我们直接进入主题吧,嘿嘿~

制做跑分工具

咱们要制做的前端性能跑分工具,主要是借助于lighthouse的这个npm包以及gulp脚本。

1.初始化项目

新建一个文件夹,小羽这里是enow-lighthouse,而后新建package.json并写入相关的内容,而后cnpm install安装咱们编写工具时所须要的一些依赖包

{
  "name": "enow-lighthouse",
  "version": "1.0.0",
  "description": "ENOW大前端——lighthouse测试工具",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start":"gulp start"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chrome-launcher": "^0.13.4",
    "del": "^6.0.0",
    "fs-extra": "^9.1.0",
    "gulp": "^4.0.2",
    "lighthouse": "^7.3.0"
  }
}
复制代码

2.编写gulp脚本

1.在根目录下建立gulpfile.js

而后在gulpfile.js中写入如下的一段代码,先测试一下咱们的项目能不能正常跑起来。若是正常的话,则会显示以下图的ENOW 大前端~

const gulp = require("gulp")
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const printer = require('lighthouse/lighthouse-cli/printer');
const Reporter = require('lighthouse/lighthouse-core/report/report-generator');
const fs = require('fs-extra');
const del = require("del")
let chrome

gulp.task("start",async function(cb){
  console.log("ENOW 大前端")
  cb()
})
复制代码

2.新增launchChrome方法,该方法是用来启动chrome的,并返回须要用到的chrome信息

  • --headless 表示不打开browser窗口
  • --disable-gpu 表示不开启gpu
  • --no-sandbox 表示不开启沙箱模式
// 开启chrome
async function launchChrome() {
  try {
      chrome = await chromeLauncher.launch({
          chromeFlags: [
              "--disable-gpu",
              "--no-sandbox",
              "--headless"
          ],
          enableExtensions: true,
          logLevel: "error"
      });
      return {
          port: chrome.port,
          chromeFlags: [
              "--headless"
          ],
          logLevel: "error"
      }
  } catch (e) {
      console.log("ENOW lighthouse error: launching Chrome ", e);
  }
}
复制代码

3.新增lighthouseRunner方法,该方法是用来跑lighthouse测试的,并返回测试结果

// 启动lighthouse测试
async function lighthouseRunner(url, opt, config={extends: 'lighthouse:default'}) {
  try {
      return await lighthouse(url, opt, config);
  } catch (e) {
      console.log("ENOW lighthouse error: running lighthouse");
  }
}
复制代码

4.新增genReport方法,该方法是用来获取当前页面报告的html页面,并返回生成的html页面

// 生成当前页面的报告
function genReport(result) {
  return Reporter.generateReport(result.lhr, 'html');
}
复制代码

5.新增run方法,该方法是每一个页面的测试入口

// 每一个页面的测试入口
async function run(url, timestamp, config) {
  let chromeOpt = await launchChrome();
  let result = await lighthouseRunner(url, chromeOpt, config);
  let report = genReport(result);
  // 保存报告
  await printer.write(report, 'html', `./cases/lighthouse-report@${timestamp}.html`);
  // 关闭chrome
  await chrome.kill();
  return
}
复制代码

6.修改gulp.task,而后在根目录下新建cases文件夹,而后运行npm run start等待一段时间后,就会发如今咱们刚刚新建的cases文件夹中生成了咱们想要的性能测试报告啦~

gulp.task("start",async function(cb){
  let taskList = [
    `https://juejin.cn/`,
    `https://juejin.cn/`,
    `https://juejin.cn/`,
  ]
  for(let item of taskList){
    let timestamp = Date.now();
    await run(item,timestamp)
  }
  cb()
})
复制代码

小羽,你在这里洋洋洒洒的写了一大堆东西,咱看着脑袋都疼了!!!

其实这里看着挺多东西的,可是逻辑仍是很容易理解滴~

待小羽给小伙伴们分析一波:

  • 首先咱们运行npm run start就会调用gulp start,接着就进入到了gulp.task()
  • 而后gulp.task()是遍历taskList,而后调用run方法(每一个页面的测试入口)
  • run方法调用launchChrome(),而后返回chrome相关信息
  • run方法调用lighthouseRunner(),而后返回测试结果
  • run方法调用genReport(),返回生成的html页面
  • run方法html页面写入到文件中
  • 关闭chrome

目前为止,gulpfile.js中的代码以下

/* * @Description: * @Author: 小羽 * @LastEditors: 小羽 * @Date: 2021-04-11 23:05:22 * @LastEditTime: 2021-04-12 00:30:55 */
const gulp = require("gulp")
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const printer = require('lighthouse/lighthouse-cli/printer');
const Reporter = require('lighthouse/lighthouse-core/report/report-generator');
const fs = require('fs-extra');
const del = require("del")
let chrome

// 开启chrome
async function launchChrome() {
  try {
      chrome = await chromeLauncher.launch({
          chromeFlags: [
              "--disable-gpu",
              "--no-sandbox",
              "--headless"
          ],
          enableExtensions: true,
          logLevel: "error"
      });
      return {
          port: chrome.port,
          chromeFlags: [
              "--headless"
          ],
          logLevel: "error"
      }
  } catch (e) {
      console.log("ENOW lighthouse error: launching Chrome ", e);
  }
}


// 启动lighthouse测试
async function lighthouseRunner(url, opt, config={extends: 'lighthouse:default'}) {
  try {
      return await lighthouse(url, opt, config);
  } catch (e) {
      console.log("ENOW lighthouse error: running lighthouse");
  }
}

// 获取当前页面的报告
function genReport(result) {
  return Reporter.generateReport(result.lhr, 'html');
}

// 每一个页面的测试入口
async function run(url, timestamp, config) {
  let chromeOpt = await launchChrome();
  let result = await lighthouseRunner(url, chromeOpt, config);
  let report = genReport(result);
  // 保存报告
  await printer.write(report, 'html', `./cases/lighthouse-report@${timestamp}.html`);
  // 关闭chrome
  await chrome.kill();
  return
}

gulp.task("start",async function(cb){
  let taskList = [
    `https://juejin.cn/`,
    `https://juejin.cn/`,
    `https://juejin.cn/`,
  ]
  for(let item of taskList){
    let timestamp = Date.now();
    await run(item,timestamp)
  }
  cb()
})
复制代码

3.抽离任务列表

通常来讲,咱们的任务列表是不会直接写在方法中,为了符合低耦合高内聚编程的思路,咱们单独把咱们的任务列表抽离出来,而后使用require引入到gulpfile.js中。在根目录下新建taskList.js

当咱们须要测某个页面的性能时,就能够把taskList.js所有改成同一个url就好。若是想测网站的总体性能,就把网站全部的URL拷贝进去就ok啦。

想知道怎么获取评分平均值以及总报告的小伙伴,请移步下一小节   (✧◡✧)

// taskList.js
module.exports = [
  `https://juejin.cn/`,
  `https://juejin.cn/`,
  `https://juejin.cn/`,
]
复制代码
// gulpfile.js
const taskList = require("./taskList")

// 省略中间的代码。。。

gulp.task("start",async function(cb){
  for(let item of taskList){
    let timestamp = Date.now();
    await run(item,timestamp)
  }
  cb()
})
复制代码

4.生成总报告

虽说咱们如今的工程也能够一键跑分了,可是有没有发现生成的文件不少,并且都得一个一个的点击进去才能看到咱们的页面信息,可不能够?

stop,别问,问就是成妾作不到!!!

哈哈哈,逗下大家啦,程序员除了产品经理提出的需求完成不了外,其余时候都是超厉害滴【手动狗头】

修改一下代码,

npm run start启动跑分程序,输出一下lighthouse跑分后的结果来瞧瞧先。

在咱们的根目录下就会生成一个file.txt文件。打开后一看。。。这啥玩意?彻底无法看呀,这可咋办?

别急,山人自有妙计

打开咱们原来生成的报表,稍微分析一下就会发现。file.txt中,lhr字段中输出的数据其实就是咱们控制台中输出的数据。那就看控制台中的数据得了呗【狗头】

新增一个write()方法,功能是输出到文件中,这里是生成咱们的总报告

// 生成总报告
async function write(file, report) {
  try {
      await fs.outputFile(file, report);
      return true
  } catch (e) {
      console.log("error while writing report ", e);
  }
}
复制代码

修改run方法,run方法中返回的数据,小伙伴们想返回那些字段本身作抉择就ok啦~

async function run(url, timestamp, num, config) {
  let chromeOpt = await launchChrome();
  let result = await lighthouseRunner(url, chromeOpt, config);
  let report = genReport(result);
  // 保存报告
  await printer.write(report, 'html', `./cases/lighthouse-report@${timestamp}-${num}.html`);
  result.lhr.audits['first-contentful-paint'].rawValue;
  let res = {
      audits:{
          "first-contentful-paint":result.lhr.audits['first-contentful-paint']
      },
      categories:result.lhr.categories,
      lighthouseVersion:result.lhr.lighthouseVersion,
      requestedUrl:result.lhr.requestedUrl
  }
  // 关闭chrome
  await chrome.kill();
  return res;//result.lhr
}
复制代码

根目录下新增summary/template/template.htmltemplate.html是咱们的总报告模板文件,小羽这里也是随便写写,小伙伴们能够自由发挥~

修改gulp.task()

gulp.task("start",async function(cb){
  let timestamp = Date.now();
  let spent = [];
  console.log(`共 ${taskList.length} 个任务`)
  for (let i = 0; i < taskList.length; i++) {
    console.log(`当前第 ${i+1} 个任务`)
    spent.push(await run(taskList[i], timestamp, i));
  }
  // 替换模板中的内容
  let template = await fs.readFileSync('./summary/template/template.html', 'utf-8');
  let summary = Reporter.replaceStrings(template, [{
    search: '%%TIME_SPENT%%',
    replacement: JSON.stringify(spent)
  }, {
    search: '%%TIMESTAMP%%',
    replacement: timestamp
  }]);
  await write(`./summary/report/summary@${timestamp}.html`, summary)
  cb()
})
复制代码

咳咳咳,提起精神来,看看咱们的成果。

npm run start后,会发如今咱们的summary/report中生成了一个新的html文件,我们打开看下

5.添加PC端和移动端的命令

emmm,不对,还有问题,由于咱们一直都是测的移动端,那咱们怎么测试pc端呀???总不能每测试一次就去修改一次配置吧?

根目录下新增constants.jslighthouse-desktop-config.js(pc端)lighthouse-mobile-config.js(移动端)

既然把移动端和pc端分开了,那原来的gulp.task()也就只有一个,不够用了,那就多加一个吧。而后方便区分,再修改一下名字为create:report-desktopcreate:report-mobile。修改gulpfile.jspackage.json

// gulpfile.js
const desktopConfig = require('./lighthouse-desktop-config.js');
const mobileConfig = require('./lighthouse-mobile-config.js');


// 省略部分代码。。。

gulp.task('create:report-desktop',async function(cb){
  let timestamp = Date.now();
  let spent = [];
  console.log(`共 ${taskList.length} 个任务`)
  for (let i = 0; i < taskList.length; i++) {
    console.log(`当前第 ${i+1} 个任务`)
    spent.push(await run(taskList[i], timestamp, i , desktopConfig));
  }
  // 替换模板中的内容
  let template = await fs.readFileSync('./summary/template/template.html', 'utf-8');
  let summary = Reporter.replaceStrings(template, [{
    search: '%%TIME_SPENT%%',
    replacement: JSON.stringify(spent)
  }, {
    search: '%%TIMESTAMP%%',
    replacement: timestamp
  }]);
  await write(`./summary/report/summary@${timestamp}.html`, summary)
  cb()
})

gulp.task('create:report-mobile',async function(cb){
  let timestamp = Date.now();
  let spent = [];
  console.log(`共 ${taskList.length} 个任务`)
  for (let i = 0; i < taskList.length; i++) {
    console.log(`当前第 ${i+1} 个任务`)
    spent.push(await run(taskList[i], timestamp, i, mobileConfig));
  }
  // 替换模板中的内容
  let template = await fs.readFileSync('./summary/template/template.html', 'utf-8');
  let summary = Reporter.replaceStrings(template, [{
    search: '%%TIME_SPENT%%',
    replacement: JSON.stringify(spent)
  }, {
    search: '%%TIMESTAMP%%',
    replacement: timestamp
  }]);
  await write(`./summary/report/summary@${timestamp}.html`, summary)
  cb()
})
复制代码
// package.json

{
  "name": "enow-lighthouse",
  "version": "1.0.0",
  "description": "ENOW大前端——lighthouse测试工具",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "create:report-desktop":"gulp create:report-desktop",
    "create:report-mobile":"gulp create:report-desktop"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chrome-launcher": "^0.13.4",
    "del": "^6.0.0",
    "fs-extra": "^9.1.0",
    "gulp": "^4.0.2",
    "lighthouse": "^7.3.0"
  }
}
复制代码

此时,咱们已经没有了start命令了,因此启动的命令就变成了npm run create:report-desktopnpm run create:report-mobile

6.删除旧的测试文件

可是小伙伴们有没有发现咱们的报表文件每次跑都会遗留下来,越积越多呀?

gulpfile.js中新增三个gulp.task()。而后修改package.json中命令

  • npm run mobile:清理文件,而后执行移动端跑分
  • npm run desktop:清理文件,而后执行pc端跑分
  • npm run clean:清理文件
  • npm run create:report-mobile:执行移动端跑分
  • npm run create:report-desktop:执行pc端跑分

这里简单的说一下,在gulp中,gulp.series()是按照顺序执行的,每次执行一个。而gulp.paralle(),则是并发运行的。

// gulpfile.js
// 清理数据
gulp.task('clean:report', function (cb) {
  del([
      'cases/**/*',
      'summary/report/**/*',
  ], cb);
  cb()
});

// gulp.series:按照顺序执行
// gulp.paralle:能够并行计算
gulp.task("start-desktop", gulp.series("clean:report","create:report-desktop"), function () {})
gulp.task("start-mobile", gulp.series("clean:report","create:report-mobile"), function () {})
复制代码
// package.json
{
  "name": "enow-lighthouse",
  "version": "1.0.0",
  "description": "ENOW大前端——lighthouse测试工具",
  "main": "index.js",
  "scripts": {
    "mobile":"gulp start-mobile",
    "desktop":"gulp start-desktop",
    "clean":"gulp clean:report",
    "create:report-desktop":"gulp create:report-desktop",
    "create:report-mobile":"gulp create:report-desktop"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chrome-launcher": "^0.13.4",
    "del": "^6.0.0",
    "fs-extra": "^9.1.0",
    "gulp": "^4.0.2",
    "lighthouse": "^7.3.0"
  }
}
复制代码

好了,如今咱们整个跑分工具就制做完成啦。若是有小伙子说他写的网页有多厉害,那就二话不说,掏出这个跑分工具,一决高下吧~

后语

本文主要是结合Google的开源项目Lighthousegulp脚本编写了一个前端性能跑分工具。主要用来帮助前端开发工程师可以更加全面的了解本身的网站/项目,快速找出优缺点,以及能够改善的方向。

相关文章
相关标签/搜索