以編程方式運行 Lighthouse 簡介

已發表: 2022-03-10
快速總結 ↬能夠以編程方式運行 Google 的 Lighthouse 分析套件提供了很多優勢,尤其是對於更大或更複雜的 Web 應用程序。 以編程方式使用 Lighthouse 允許工程師為需要更多自定義的站點設置質量監控,而不是 Lighthouse 的直接應用程序(例如 Lighthouse CI)所允許的。 本文簡要介紹了 Lighthouse,討論了以編程方式運行它的優勢,並介紹了基本配置。

Lighthouse 是 Google 的一套網站質量分析工具。 它允許您評估網站的性能、可訪問性、SEO 等。 它也是高度可配置的,使其足夠靈活以適用於所有站點,從最簡單到高度複雜。 這種靈活性包括幾種不同的測試運行方式,允許您選擇最適合您的站點或應用程序的方法。

運行 Lighthouse 的最簡單方法之一是通過 Chrome 的 DevTools Lighthouse 面板。 如果您在 Chrome 中打開您的網站,然後打開 Chrome 的 DevTools,您應該會看到一個“Lighthouse”選項卡。 從那裡,如果您單擊“生成報告”,您應該會獲得有關您網站質量指標的完整報告。

然而,我在這篇文章中關注的是光譜的另一端。 使用 JavaScript 以編程方式運行 Lighthouse 允許我們配置自定義運行、挑选和選擇我們想要測試的功能、收集和分析結果以及指定我們的站點和應用程序獨有的配置選項。

例如,也許您在一個可通過多個 URL 訪問的站點上工作——每個 URL 都有自己的數據和样式,甚至可能還有您希望能夠分析的標記。 或者,也許您想從每個測試運行中收集數據並以不同的方式編譯或分析它。 能夠根據最適合您的站點或應用程序的方式來選擇您希望如何運行 Lighthouse 分析,這樣可以更輕鬆地監控站點質量並在問題堆積或給您造成太多問題之前查明您的站點存在的問題網站的用戶。

以編程方式運行 Lighthouse 並不是每個站點的最佳選擇,我鼓勵您探索 Lighthouse 團隊為使用該工具而構建的所有不同方法。 但是,如果您決定以編程方式使用 Lighthouse,那麼下面的信息和教程應該可以幫助您入門。

自定義燈塔選項

以編程方式運行 Lighthouse 的優勢不僅在於能夠配置 Lighthouse 本身,還在於您可能想要或需要圍繞 Lighthouse 測試做的所有事情。 Lighthouse 有一些很棒的文檔可以幫助您入門。 然而,為了充分利用以編程方式運行它,您需要深入了解 Lighthouse 如何工作的兩個主要方面:配置測試運行和報告測試結果。

Lighthouse 測試運行配置

配置 Lighthouse 測試運行是您喜歡的簡單或複雜的任務之一。

以編程方式運行 Lighthouse 時,您可以在三個位置提供自定義選項:您將測試的 URL、Chrome 選項和 Lighthouse 配置對象。 您可以從 Lighthouse 文檔中看到這三個都是運行 Lighthouse 的函數中的參數:

 function launchChromeAndRunLighthouse(url, opts, config = null) { return chromeLauncher.launch({chromeFlags: opts.chromeFlags}).then(chrome => { opts.port = chrome.port; return lighthouse(url, opts, config).then(results => { return chrome.kill().then(() => results.lhr) }); }); }

您可以使用所需的任何代碼來創建這些參數。 例如,假設您有一個包含多個要測試的頁面或 URL 的站點。 也許您想在 CI 環境中運行該測試作為 CI 任務的一部分,每次任務運行時檢查所有必要的頁面。 使用此設置,您可以使用 JavaScript 創建 URL 並創建一個循環,該循環將為每個 URL 運行 Lighthouse。

您可能需要的任何 Chrome 選項都可以在傳遞給 chrome-launcher 的對像中指定。 在文檔中的示例中, opts對象包含一個我們稱為chromeFlags的數組,您可以將其傳遞給 chrome-launcher 和一個端口,您可以在其中保存 chrome-launcher 正在使用的端口,然後將其傳遞給 Lighthouse。

最後,Lighthouse 配置對象允許您添加任何特定於 Lighthouse 的選項。 Lighthouse 包提供了一個默認配置對象,可以按原樣使用或擴展和修改。 您可以使用此對象執行多種操作,包括指定要測試的 Lighthouse 測試類別。

跳躍後更多! 繼續往下看↓

您可以使用emulatedFormFactor來指定是否希望測試在移動或桌面模擬器中運行。 您可以使用extraHeaders添加您可能需要在瀏覽器中使用的任何 cookie。 例如,在將結果輸出為 HTML 的桌面模擬器上僅運行可訪問性類別的測試可能具有如下所示的配置對象:

 const lighthouseOptions = { extends: 'lighthouse:default', settings: { onlyCategories: ['accessibility'], emulatedFormFactor:'desktop', output: ['html'], }, }

此示例表示最小配置。 你可以做的還有很多。 Lighthouse 配置文檔有更多信息。 它們還有一組示例配置對象,用於一些更複雜的實現。

自定義結果報告

以編程方式運行 Lighthouse 時,您可以以三種格式選項中的一種或多種形式返回結果,並且 - 這是我認為最令人興奮的部分 - 您可以訪問原始 Lighthouse Result (LHR) 對象。

HTML、JSON、CSV

Lighthouse 將自動以三種不同的方式格式化結果:HTML、JSON 或 CSV。 這些都是基於基本 Lighthouse 報告模板的預配置結果,例如,如果您在 Chrome DevTools 中運行 Lighthouse 測試,您會看到這些結果。 在上一節的lighthouseOptions配置對像中,您可以看到一個用於output的鍵,其中包含一個帶有單個字符串的數組: html 。 這指定我只希望返回格式為 HTML 的結果。 如果我想要 HTML 和 JSON 格式的結果,則該數組看起來像['html', 'json']

一旦 Lighthouse 運行,它將返回一個包含兩個鍵的結果對象: reportlhr 。 我們將在下一節討論lhr鍵的內容,但report鍵包含一個數組,其中的結果按照您的要求格式化。 因此,例如,如果我們請求了['html', 'json'] ,那麼results.report[0]將包含我們格式化為 HTML 的結果,而results.report[1]將包含我們格式化為 JSON 的結果。

LHR 對象

以編程方式運行 Lighthouse 還可以讓您訪問更靈活的結果對象:LHR 對象。 該對象包含 Lighthouse 運行的原始結果和一些元數據。 更完整的文檔可以在 Lighthouse Github 存儲庫中找到。

您可以通過多種方式使用這些結果,包括創建自定義報告和從多次運行中收集數據進行分析。

示例:針對移動設備和桌面設備運行可訪問性測試

假設我有一個站點,它根據用戶使用的是小屏幕還是大屏幕來加載不同的組件,這意味著每個版本的站點的 HTML 都會略有不同。 我想確保站點的兩個版本在 Lighthouse 可訪問性測試中都獲得 95 分,並且沒有代碼被提交到不符合該標準的main分支。

注意如果您想查看下面分析 Sparkbox 主頁的代碼的工作示例,您可以在此處找到存儲庫。

我可以將 Lighthouse 配置為運行可訪問性類別兩次,為每一個提供不同的配置對象——一次將emulatedFormFactor設置為desktop ,另一次將其設置為mobile 。 一個簡單的方法是創建一個包含兩個對象的數組,如下所示。

 const lighthouseOptionsArray = [ { extends: 'lighthouse:default', settings: { onlyCategories: ['accessibility'], emulatedFormFactor:'desktop', output: ['html', 'json'], }, }, { extends: 'lighthouse:default', settings: { onlyCategories: ['accessibility'], emulatedFormFactor:'mobile', output: ['html', 'json'], }, }, ]

然後,我可以創建一個函數,該函數將遍歷這個數組,並為在數組中找到的每個對象運行 Lighthouse 測試。

需要注意的一點是,每次運行之間必須引入延遲,否則 Chromium 可能會混淆並且運行會出錯。 為了做到這一點,我添加了一個wait函數,它在setTimeout間隔完成時返回一個承諾。

 function wait(val) { return new Promise(resolve => setTimeout(resolve, val)); } function launchLighthouse(optionSet, opts, results) { return chromeLauncher .launch({ chromeFlags: opts.chromeFlags }) .then(async chrome => { opts.port = chrome.port; try { results = await lighthouse(url, opts, optionSet); } catch (e) { console.error("lighthouse", e); } if (results) reportResults(results, runEnvironment, optionSet, chrome); await wait(500); chrome.kill(); }); } async function runLighthouseAnalysis() { let results; const opts = { chromeFlags: ["--no-sandbox", "--headless"] }; for (const optionSet of lighthouseOptionsArray) { console.log("****** Starting Lighthouse analysis ******"); await launchLighthouse(optionSet, opts, results); } }

在這種情況下,我將結果發送到reportResults函數。 從那裡,我將結果保存到本地文件,將結果打印到控制台,並將結果發送到一個函數,該函數將確定測試是否通過了我們的可訪問性閾值。

 async function reportResults(results, runEnvironment, optionSet, chrome) { if (results.lhr.runtimeError) { return console.error(results.lhr.runtimeError.message); } await writeLocalFile(results, runEnvironment, optionSet); printResultsToTerminal(results.lhr, optionSet); return passOrFailA11y(results.lhr, optionSet, chrome); }

對於這個項目,我希望能夠將 JSON 結果保存在我們的 CI 測試運行的指定目錄中,並將 HTML 文件保存在我們的本地測試運行的指定目錄中。 Lighthouse 返回這些不同類型結果的方式是按照請求的順序排列在一個數組中。

因此,在本例中,在我們的lighthouseOptions對像中,我們的數組首先請求 HTML,然後是 JSON。 因此, report數組將首先包含 HTML 格式的結果,然後是 JSON 格式的結果。 然後writeToLocalFile函數將結果的正確版本保存在具有自定義名稱的文件中。

 function createFileName(optionSet, fileType) { const { emulatedFormFactor } = optionSet.settings; const currentTime = new Date().toISOString().slice(0, 16); const fileExtension = fileType === 'json' ? 'json' : 'html'; return `${currentTime}-${emulatedFormFactor}.${fileExtension}`; } function writeLocalFile(results, runEnvironment, optionSet) { if (results.report) { const fileType = runEnvironment === 'ci' ? 'json' : 'html'; const fileName = createFileName(optionSet, fileType); fs.mkdirSync('reports/accessibility/', { recursive: true }, error => { if (error) console.error('error creating directory', error); }); const printResults = fileType === 'json' ? results.report[1] : results.report[0]; return write(printResults, fileType, `reports/accessibility/${fileName}`).catch(error => console.error(error)); } return null; }

我還想在測試運行完成時將結果打印到終端。 這提供了一種快速簡便的方法來查看結果,而無需打開文件。

 function printResultsToTerminal(results, optionSet) { const title = results.categories.accessibility.title; const score = results.categories.accessibility.score * 100; console.log('\n********************************\n'); console.log(`Options: ${optionSet.settings.emulatedFormFactor}\n`); console.log(`${title}: ${score}`); console.log('\n********************************'); }

最後,如果可訪問性分數不符合我的閾值分數 95,我希望能夠通過測試運行。

 function passOrFailA11y(results, optionSet, chrome) { const targetA11yScore = 95; const { windowSize } = optionSet; const accessibilityScore = results.categories.accessibility.score * 100; if (accessibilityScore) { if (windowSize === 'desktop') { if (accessibilityScore < targetA11yScore) { console.error(`Target accessibility score: ${targetA11yScore}, current accessibility score ${accessibilityScore}`); chrome.kill(); process.exitCode = 1; } } if (windowSize === 'mobile') { if (accessibilityScore < targetA11yScore) { console.error(`Target accessibility score: ${targetA11yScore}, current accessibility score ${accessibilityScore}`); chrome.kill(); process.exitCode = 1; } } } }

我邀請大家一起玩,並探索 Lighthouse 可以幫助監控您的網站質量的所有不同方式。

最後的筆記

雖然我故意讓上面的示例相對簡單,但我希望它能讓您很好地了解以編程方式運行 Lighthouse 時可以完成的工作。 我希望它能激發您找到使用這個靈活、強大工具的新方法。

正如彼得·德魯克所說:

“如果你不能衡量它,你就不能改進它。”

不僅能夠衡量而且監控我們的網站質量,尤其是對於復雜的網站,將大大有助於我們建立更好的網絡。

關於 SmashingMag 的進一步閱讀

  • 移動優先體驗的 A/B 測試
  • 如何測試設計概念的有效性
  • 手動可訪問性測試的重要性
  • 使用 Tensorflow.js 為前端開發人員提供機器學習
  • 使用這些技巧開始 UI 設計以加快您的工作流程

當然,在 Smashing Workshops 中,Smashing Cat 探索新的見解。

有用的前端和用戶體驗位,每週交付一次。

借助工具幫助您更好地完成工作。 通過電子郵件訂閱並獲取 Vitaly 的智能界面設計清單 PDF

在前端和用戶體驗上。 受到 190.000 人的信賴。