希沃ENOW大前端javascript
公司官网:CVTE(广州视源股份)html
团队:CVTE旗下将来教育希沃软件平台中心enow团队前端
本文做者:java
hello
,你们好,我是小羽同窗。一个平凡,而又不甘于平凡的前端开发工程师!git
你们对跑分应该挺熟悉了吧?尤为是米粉,雷老板的那句不服?那就跑个分!
应该历历在目吧?哈哈哈程序员
在平常的前端开发过程当中,小伙伴们或多或少都有接触过性能优化吧?可是你日常是怎么肯定性能是否获得了提高呢?Google
的开源工具——Lighthouse
也就应运而生。github
Lighthouse
主要是用于分析网络应用和网页,收集现代性能指标并提供对开发人员最佳实践的意见。对于前端开发工程师来讲,能够简洁明了得看到项目中的不足之处,以及优化的方法。是平常开发中不可多得的神器呀!web
chrome
的商店中,搜索lighthouse
,而后添加。chrome
而后在chrome
顶部的插件栏中打开插件。点击设置图标,还能够选择进行测试(跑分)的项目,以及是测试pc
端仍是手机端的网页。npm
而后咱们直接点击generate report
按钮便可直接进入测试,过一段时间后结果就会出来啦。下面那个图就是咱们ENOW 大前端团队
的掘金首页测试评分啦,能够看到掘金
的seo
优化作的仍是很是棒的,哈哈哈~
整个测试报告中给咱们标明了页面中的各类性能相关的参数,而后也给到了咱们不少相关的优化建议。小伙伴们以为感兴趣的话,能够深刻的去了解各个参数哦~
如今性能测试工具备是有了,可是有没有发现这个就只能一个一个页面的去测,好麻烦呀。若是有几十个页面还得一个一个的去点。大家会不嫌麻烦嘛?反正像小羽同窗这么厌倦重复性工做的人来讲,早就烦死了 (╯°Д°)╯︵┻━┻
如今问题来了,那有没有什么方便的方法呀?一个一个的去点着测试总不是方法呀。
别着急,干货立刻就到啦~
其实除了chrome
插件的使用方式,咱们还可使用命令行
的方式来调用Lighthouse
。
1.全局安装 lighthouse
npm install -g lighthouse
复制代码
2.输入你的页面
lighthouse http://test.com
复制代码
小羽在这里就不进行展现了,我们直接进入主题吧,嘿嘿~
咱们要制做的前端性能跑分工具,主要是借助于lighthouse的这个npm
包以及gulp
脚本。
新建一个文件夹,小羽这里是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"
}
}
复制代码
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()
})
复制代码
通常来讲,咱们的任务列表是不会直接写在方法中,为了符合低耦合
、高内聚
编程的思路,咱们单独把咱们的任务列表抽离出来,而后使用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()
})
复制代码
虽说咱们如今的工程也能够一键
跑分了,可是有没有发现生成的文件不少,并且都得一个一个的点击进去才能看到咱们的页面信息,可不能够?
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.html
,template.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
文件,我们打开看下
emmm
,不对,还有问题,由于咱们一直都是测的移动端,那咱们怎么测试pc
端呀???总不能每测试一次就去修改一次配置吧?
根目录下新增constants.js、lighthouse-desktop-config.js(pc端)、lighthouse-mobile-config.js(移动端)
既然把移动端和pc端分开了,那原来的gulp.task()也就只有一个,不够用了,那就多加一个吧。而后方便区分,再修改一下名字为create:report-desktop
和create:report-mobile
。修改gulpfile.js
,package.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-desktop
和npm run create:report-mobile
可是小伙伴们有没有发现咱们的报表文件每次跑都会遗留下来,越积越多呀?
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
的开源项目Lighthouse
和 gulp脚本
编写了一个前端性能跑分工具。主要用来帮助前端开发工程师可以更加全面的了解本身的网站/项目,快速找出优缺点,以及能够改善的方向。