希沃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腳本
編寫了一個前端性能跑分工具。主要用來幫助前端開發工程師可以更加全面的瞭解本身的網站/項目,快速找出優缺點,以及能夠改善的方向。