本文主要是記錄如何在專案中簡易下指令來自動執行 Lighthouse 與 Puppeteer 做全站網頁的效能檢測、產生報表與其目錄。
Lighthouse 是由 Google 開發的開源自動化檢測網站效能的工具,檢測後能給出有建設性的建議,直接告訴我們 要改善什麼地方、要怎麼改,而且還有文件可查、有範例可看,能參考的資源很多,並且會將檢測結果和建議產出人機皆可閱讀的報表。除了效能,它還有檢測其他項目,像是 SEO、PWA,功能多多。
使用 Lighthouse 有幾種方法,有以下幾種
這裡主要是選用 Lighthouse Node CLI 來做全站各頁的檢測,這是因為稍等會看到…要檢測的網站有些頁面是需要登入的,只靠 Lighthouse 恐怕不夠用,還需搭配 End-to-End Testing 工具才能完成工作。
雖然能做效能檢測的工具很多,除了 Lighthouse,還有 PageSpeed Insights、WebPage Test、Pingdom 等,相關介紹可參考這裡…這些工具各有自己的長處,但 Lighthouse 提供 Node CLI 版本,易於和自動化工具,因此就選用它了。
如前所述,由於要檢測的網站有些頁面是需要登入的,因此需要搭配 End-to-End Testing 工具做登入的動作,並導頁到要檢測的頁面來做檢測,這裡選用 Puppeteer;再來,Lighthouse 並不會幫我們做產出報表的目錄,因此我找了 Table-Builder 來協助製作目錄的表格…綜合以上需求,就必須安裝 Lighthouse、Puppeteer、Table-Builder 與 fs。
yarn add lighthouse puppeteer table-builder fs
備註,除了 Puppeteer,可選用的 End-to-End Testing 工具很多,像是 WebdriverIO、Nightwatch 都可以。
如前所述,直接使用 Lighthouse 來檢測需要登入的頁面是不可行的因為根本看不到啊,要怎麼檢測解決方法是先使用 Puppeteer 來做登入,而由於要借助 End-to-End Testing 工具來做登入的動作,並導頁到要檢測的頁面來做檢測,因此就要寫一支測試程式來做這些事情。
以下程式碼片段會做以下幾件事情…
(1) 到達首頁。
(2) 點擊「登入按鈕」。
(3) 輸入帳號、密碼。
(4) 輸入密碼。
(5) 送出輸入的帳號、密碼,登入成功。
程式碼片段說明如下…
async function navigateToIndex() { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); const indexURL = context['env'] === 'DEV' ? DEV_HOST : PROD_HOST; console.log('Navigating to index...'); await page.goto(ENV); // (1) 到達首頁 console.log('Starting login, entering username and password...'); await page.click('#login'); // (2) 點擊「登入按鈕」 await page.type('#account', 'test'); // (3) 輸入帳號 await page.type('#password', 'test'); // (4) 輸入密碼 await page.click('#submit'); // (5) 送出輸入的帳號、密碼 console.log('Login success!'); // 登入成功 return browser;}
接下來,依舊使用 Puppeteer 幫我們遍歷全站網頁,並針對每個網頁用 Lighthouse 做檢測,然後產出報表。
如下程式碼,TEST_PAGES 是一個存放頁面列表的常數變數(例如:這個存放頁面列表的常數變數可能是長成這樣 [{id: '...', link: '...'}]
),利用 for 迴圈將整個網站的每個頁面都跑一遍;當中使用 Lighthouse 檢測,這裡會產出兩種格式的報表-HTML 與 JSON,再利用 Lighthouse 內建的 reportGenerator 畫出報表;最後使用 TableBuilder 做總結,產生一份簡單的目錄來作 report cover。
以下程式碼片段會做以下幾件事情…
(1) 存放所有的 overview 紀錄,等等做目錄用。
(2) 將整個網站的每個頁面跑一次。
(3) 產出兩種格式的報表-HTML 與 JSON。
(4) overview 所需的資料,包含 「Performance」、「Accessibility」、「Best Practices」、「SEO」、「Progressive Web App」五個項目與其分數,分數以小數點表示,滿分為 1。
(5) 產生每頁的報表。
程式碼片段說明如下…
browser = await navigateToIndex();page = (await browser.pages())[0];const records = []; // (1) 存放所有的 overview 紀錄,等等做目錄用console.log('Running Lighthouse...');for (let i = 0; i < TEST_PAGES.length; i += 1) { // (2) 將整個網站的每個頁面跑一次 const report = await lighthouse( `${ENV}${TEST_PAGES[i].link}`, { // lighthouse 檢測中... port: new URL(browser.wsEndpoint()).port, output: 'json', logLevel: 'info', disableDeviceEmulation: true, chromeFlags: ['--disable-mobile-emulation'], }, config, ); // (3) 產出兩種格式的報表-HTML 與 JSON const json = reportGenerator.generateReport(report.lhr, 'json'); const html = reportGenerator.generateReport(report.lhr, 'html'); const categories = Object.values(report.lhr.categories); const record = {}; console.log(`Review results for ${TEST_PAGES[i].id}...`); record[ 'Page' ] = `<a href='./lighthouse-results-${TEST_PAGES[i].id}.html' target='blank'>${TEST_PAGES[i].id}</a>`; // (4) overview 所需的資料,包含 「Performance」、「Accessibility」、「Best Practices」、「SEO」、「Progressive Web App」五個項目與其分數,分數以小數點表示,滿分為 1 for (let i = 0; i < categories.length; i += 1) { const key = `${categories[i].title}`; record[key] = categories[i].score; console.log(`Lighthouse scores: ${categories[i].title} ${categories[i].score}`); } records.push(record); // (5) 產生每頁的報表 console.log('Writing results...'); fs.writeFileSync(`reports/performance/lighthouse-results-${TEST_PAGES[i].id}.json`, json); fs.writeFileSync(`reports/performance/lighthouse-results-${TEST_PAGES[i].id}.html`, html);}
報表產生好了,但總需要有目錄和簡述到底成果如何吧?因此這裡會做一個簡單的目錄,並列出每一頁「Performance」、「Accessibility」、「Best Practices」、「SEO」、「Progressive Web App」五個項目的個別分數。
以下程式碼片段會做以下幾件事情…
(1) 設定表頭,包含 「Performance」、「Accessibility」、「Best Practices」、「SEO」、「Progressive Web App」五個項目。
(2) 使用 TableBuilder 產生一份簡單的目錄。
(3) 將產出的結果寫入 HTML 檔案。
程式碼片段說明如下…
// (1) 設定表頭,包含 「Performance」、「Accessibility」、「Best Practices」、「SEO」、「Progressive Web App」五個項目const headers = { Page: 'Page', Performance: 'Performance', Accessibility: 'Accessibility', 'Best Practices': 'Best Practices', SEO: 'SEO', 'Progressive Web App': 'Progressive Web App',};// (2) 使用 TableBuilder 產生一份簡單的目錄const table = new TableBuilder({ class: 'repor-table' }) .setHeaders(headers) // see above json headers section .setData(records) // see above json data section .render();// (3) 將產出的結果寫入 HTML 檔案fs.writeFileSync(`reports/performance/lighthouse-report-index.html`, table);
產生的目錄如下圖所示(很陽春,待改善 ╮(╯_╰)╭
)。
點此看產生的目錄檔範例。
完整程式碼可參考這裡。
這裡寫了幾種檢測效能的 script-檢測單一頁面、依照開發或正式機環境做檢測。
指定單一網址做檢測,yarn lighthouse
後可接受一個網址。注意,這只適用於不用登入的頁面。
yarn lighthouse https://next-meal.vercel.app/
依照開發環境做檢測,由於有搭配 End-to-End Testing 工具來做登入,因此適用需要登入的頁面,且能做全站網頁檢測。
yarn perf-dev
依照正式機環境做檢測,同上,由於有搭配 End-to-End Testing 工具來做登入,因此適用需要登入的頁面,且能做全站網頁檢測。
yarn perf-prod
package.json
的設定範例如下,或參考這裡。
"lighthouse": "./node_modules/lighthouse/lighthouse-cli/index.js --output-path=./reports/performance/lighthouse-results.html $url","perf-dev": "node test/performance/index.js --env=DEV","perf-prod": "node test/performance/index.js --env=PROD"
之後會有文章來記錄結合 CI/CD、將以上使用 Lighthouse 與 Puppeteer 做檢測的方式抽出來成為一個單獨的工具的文章,敬請期待 (๑·̀ㅂ·́)و✧
ERR_SSL_PROTOCOL_ERROR when making requests between docker containers
Making Better Use of Lighthouse with Puppeteer:本文的解法主要是參考這篇文章。
Variables in package.json:設定參考本身檔案的變數,如果只是要帶變數就在前面加一個錢字號即可。
联系客服