Lighthouse架構剖析

blank

Lighthouse架構剖析

Lighthouse

Lighthouse是Google開發的一款開源工具,提供一套全面的測試來評估網頁品質,包括載入性能、可訪問性、最佳實踐和PWA。 在chrome 60之後的版本,DevTool里已經內置了Lighthouse。

Lighthouse的目標是"Do Better Web",旨在説明Web開發者改進他們現有的Web應用程式。 通過運行一整套的測試,開發者可以發現新的 Web 平臺 API,意識到性能的隱患,並學習(新的)最佳實踐。 換句話說,就是讓開發者在 Web 開發上做得更好。

如何使用

開發者工具

在chrome 60之後,DevTools里已經內置了Lighthouse,選擇Audits這個tab,選擇想測試的分類,點擊Run audit,等幾十秒之後即可看到測試報告

blank

報告里會顯示得分和每個測試項的測試情況

blank

命令行

全域安裝Lighthouse

npm install -g lighthouse

然後

lighthouse https://taobao.com/

lighthouse命令提供了很多選項,以下幾個是需要注意的:

  • --chrome-flags
    用來傳入chrome命令行參數,chrome命令行參數是Chrome為了實現實驗性功能、方便調試、延伸選項而做的特殊功能,目前已經提供了一千多個參數,完整清單點這裡,其中有些參數在伺服器部署和運行chrome的時候很有用。
  • --disable-storage-reset
    在運行前 不清空 瀏覽器緩存和其他storage API,可以用來測二次訪問的性能情況
  • --disable-device-emulation
    Lighthouse預設會用Nexus 5X的模擬器來測試頁面,可以用這個選項禁用掉,尤其是測試PC端頁面的時候
  • --disable-network-throttling
    Lighthouse預設會類比使用fast 3G的網速,使用這個參數禁用掉網速類比

作為node模組

可以將Lighthouse作為一個node模組,在自己的工程裡調用

constlighthouse=require('lighthouse');constchromeLauncher=require('chrome-launcher');functionlaunchChromeAndRunLighthouse(url,opts,config=null){// 先使用chrome launcher打开一个chrome窗口
returnchromeLauncher.launch({chromeFlags:opts.chromeFlags}).then(chrome=>{opts.port=chrome.port;// 然后再相同的端口运行lighthouse
returnlighthouse(url,opts,config).then(results=>chrome.kill().then(()=>results));});}constopts={chromeFlags:['--show-paint-rects']};// Usage:
launchChromeAndRunLighthouse('https://example.com',opts).then(results=>{// Use results!
});

Lighthouse架構

blank

Lighthouse裡主要的模組有些下面幾個:

  • Driver 驅動,封裝了一層和Chrome Debugging Protocol進行交互的介面
  • Gather 收集器,使用Driver收集頁面的一些訊息,以及一些數據的處理,Gather收集到的數據稱為Artifacts
  • Audit 審查,將Artifacts作為輸入,通過一些規則和計算,得到是否通過或者這一項審查的得分
  • Config 配置,配置需要運行哪些Gather和Audit,以及Audit的分類和得分權重等訊息

整個運行過程:讀取本次運行的Config,執行Config里的Gather,收集到所有需要的頁面訊息,接著按順序執行Config里的Audit清單,得到每個Audit的執行結果,根據Config里的分類和權重計算,得到最後的報告,報告結果可以是json也可以是html

下面分別介紹各個模組

Driver

Driver封裝了一些操控頁面和獲取頁面數據的常用API,其實現就是基於Chrome Debugging Protocol

Chrome Debugging Protocol可能有些童鞋會感到陌生,但是Chrome DevTools大家一定用過,Chrome DevTools是用HTML,Javascript,CSS編寫的chrome開發者工具,Chrome Debugging Protocol就是它用來與瀏覽器頁面(pages)交互和調試的協定通道。

舉個栗子比較直觀~

用下面的命令打開chrome

open -a "/Applications/Google Chrome.app" --args --remote-debugging-port=9222

隨意打開一個頁面,然後訪問 http://localhost:9222/

blank

點擊阿裡小蜜,可以看到打開了一個url為 http://localhost:9222/devtools/inspector.html?ws=localhost:9222/devtools/page/(3D979760CFFE11B397EA1EE0F26200BE) 的頁面,這個其實就是Chrome DevTools

觀察一下url,可以發現,通過querystring告訴了DevTools,應該連接到哪個WebSocket。 既然DevTools本身是個html頁面,我們也可以調試它

blank

注意到WebSocket,發送消息裡的method有 Network.enable 這種方法,這些就是Chrome Debugging Protocol提供的方法,所有方法點這裡查看

同樣的,Lighthouse的Driver也是通過WebSocket,使用Chrome Debugging Protocol和頁面交互,以及收集頁面的載入性能、DOM、Network等數據

sendCommand是Driver裡的核心方法,用來調用Chrome Debugging Protocol

/**
 * Call protocol methods
 * @param {!string} method
 * @param {!Object} params
 * @param {{silent: boolean}=} cmdOpts
 * @return {!Promise}
 */sendCommand(method,params,cmdOpts){constdomainCommand=/^(w+).(enable|disable)$/.exec(method);if(domainCommand){constenable=domainCommand[2]==='enable';if(!this._shouldToggleDomain(domainCommand[1],enable)){returnPromise.resolve();}}returnthis._connection.sendCommand(method,params,cmdOpts);}

Gathers

Gathers收集器,Lighthouse裡有很多的Gather,用來收集不同的數據。 以 ChromeConsoleMessages 為例,這個Gather用來獲取console里列印的訊息。

beforePassafterPass 分別是在打開測試頁面前,和所有pass裡的gather都運行完之後開始調用,Driver會作為參數傳到Gather的函數里(後面會有文章詳細介紹Gather的流程,這裡不展開)。 以下代碼的含義就是在頁面打開前,開啟Log收集,在頁面載入完之後結束,console里的數據通過監聽 Log.entryAdded 事件獲取到

beforePass(options){constdriver=options.driver;driver.on('Log.entryAdded',this._onConsoleEntryAdded);returndriver.sendCommand('Log.enable').then(()=>driver.sendCommand('Log.startViolationsReport',{config:[{name:'discouragedAPIUse',threshold:-1}],}));}afterPass(options){returnPromise.resolve().then(_=>options.driver.sendCommand('Log.stopViolationsReport')).then(_=>options.driver.off('Log.entryAdded',this._onConsoleEntryAdded)).then(_=>options.driver.sendCommand('Log.disable')).then(_=>this._logEntries);}

收集到的Gather數據會經過處理,返回Artifacts

Audits

Audits是Lighthouse的核心,最終的測試報告就是通過Audits裡的各種計算和判斷規則得到的。 依然舉個簡單的栗子,我們收集到了console里的數據,要實現一個Audit來判斷console里是否有報錯

audit函數是每個Audits都會實現的核心函數,這個函數會有 artifacts 作為入參,上面例子里通過 ChromeConsoleMessages 收集到console訊息,就可以通過 artifacts.ChromeConsoleMessages 得到。 拿到console數據之後就簡單了,判斷下類型,組裝數據,返回結果

staticaudit(artifacts){constconsoleEntries=artifacts.ChromeConsoleMessages;construntimeExceptions=artifacts.RuntimeExceptions;constconsoleRows=consoleEntries.filter(log=>log.entry&&log.entry.level==='error').map(item=>{return{source:item.entry.source,description:item.entry.text,url:item.entry.url,};});construntimeExRows=runtimeExceptions.filter(entry=>entry.exceptionDetails!==undefined).map(entry=>{return{source:'Runtime.exception',description:entry.exceptionDetails.exception.description,url:entry.exceptionDetails.url,};});consttableRows=consoleRows.concat(runtimeExRows);constheadings=[{key:'url',itemType:'url',text:'URL'},{key:'description',itemType:'text',text:'Description'},];constdetails=Audit.makeTableDetails(headings,tableRows);constnumErrors=tableRows.length;return{score:numErrors===0,rawValue:numErrors,extendedInfo:{value:tableRows,},details,};}

Config

有了很多Gather和Audits,怎麼知道這次測試需要運行哪些呢,這就是通過Config來實現的。 Lighthouse預設提供了幾套config,也支援自定義config,典型的配置結構可以看Lighthouse的默認配置,字段和含義如下

欄位名稱 型態 用處
extends string boolean
settings Object undefined
passes Object[] 每個pass會重新載入一次頁面,pass裡需要指定需要運行的Gather
audits string[] 需要運行的audits清單
categories string[] audits分類以及得分權重
groups string[] audits分類里的分組

總結

本文介紹了Lighthouse的使用和架構,後面會有系列文章介紹如何基於Lighthouse二次開發,如何自定義audit和gather,如何測試需要登錄鑒權的網站等,敬請期待~

想了解更多關於 Facebook 與 Google 廣告投放?

What do you think?

Written by marketer

blank

【5分鐘玩轉Lighthouse】搭建bitwarden個人密碼管理器

blank

每一個開發者都必裝的十大 Chrome 外掛程式