AutoWebPerf を使ってみる
こちらのスクラップは下記記事にまとめました👍
AutoWebPerf
Google が作った複数のソースからパフォーマンスのデータを自動的に収集できるツール
- Chrome UXレポート
- PageSpeed Insights
- WebPageTest
スプレッドシートに書き込んだり、DataStudio で可視化したりを自動化する
アーキテクチャ
コネクタからテストのリストを取得し、ギャザラーを介してパフォーマンスを取得し、コネクタに結果を出力する
- the engine
- connector modules
- スプレッドシート
- JSON
- CSV
- gatherer modules
- CrUX API
- CrUX BigQuery
- PageSpeed Insights API
- WebPageTest API
クイックスタート
git clone https://github.com/GoogleChromeLabs/AutoWebPerf.git
cd AutoWebPerf
npm i
./awp run examples/tests.json output/results.json
{
"tests": [
{
"label": "web.dev",
"url": "https://web.dev",
"gatherer": "psi"
}
]
}
結果は下記
{
"results": [
{
"id": "1610180070705-https://web.dev",
"type": "Single",
"gatherer": "psi",
"status": "Retrieved",
"label": "web.dev",
"createdTimestamp": 1610180070705,
"modifiedTimestamp": 1610180070705,
"errors": [],
"url": "https://web.dev",
"psi": {
"status": "Retrieved",
"statusText": "Success",
"settings": {},
"metadata": {
"testId": "https://web.dev/",
"requestedUrl": "https://web.dev/",
"finalUrl": "https://web.dev/",
"lighthouseVersion": "6.3.0",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/85.0.4183.140 Safari/537.36",
"fetchTime": "2021-01-09T08:14:31.866Z"
},
"metrics": {
"RenderBlockingResources": 0,
"crux": {
"LargestContentfulPaint": {
"category": "FAST",
"percentile": 2475,
"good": 0.761798544259217,
"ni": 0.15437896219769925,
"poor": 0.08382249354308509
},
"FirstInputDelay": {
"category": "FAST",
"percentile": 17,
"good": 0.9399224806201529,
"ni": 0.04069767441860455,
"poor": 0.01937984496124033
},
"FirstContentfulPaint": {
"category": "AVERAGE",
"percentile": 2521,
"good": 0.18828643331045844,
"ni": 0.6437886067261603,
"poor": 0.16792495996339965
},
"CumulativeLayoutShift": {
"category": "FAST",
"percentile": 3,
"good": 0.7931119920713579,
"ni": 0.07210109018830525,
"poor": 0.13478691774033683
}
},
"lighthouse": {
"FirstContentfulPaint": 1411,
"FirstMeaningfulPaint": 1682,
"LargestContentfulPaint": 3318.111530962102,
"SpeedIndex": 2162,
"TimeToInteractive": 5448,
"FirstCPUIdle": 4085,
"FirstInputDelay": 13,
"TotalBlockingTime": 109,
"CumulativeLayoutShift": 0,
"TotalSize": 392,
"HTML": 7,
"Javascript": 140,
"CSS": 25,
"Fonts": 74,
"Images": 135,
"Medias": 0,
"ThirdParty": 202,
"UnusedCSS": 21,
"WebPImages": 0,
"OptimizedImages": 0,
"ResponsiveImages": 0,
"OffscreenImages": 0,
"DOMElements": 307,
"Performance": 0.88,
"ProgressiveWebApp": 1,
"Manifest": 1,
"ServiceWorker": 1,
"Offline": 1,
"Accessibility": 1,
"SEO": 0.99,
"BestPractices": 1
}
},
"errors": []
}
}
]
}
定期的なテスト
準備
./awp recurring examples/tests-recurring.json output/results.json
{
"tests": [
{
"label": "web.dev",
"url": "https://web.dev",
"recurring": {
"frequency": "Daily",
"nextTriggerTimestamp": 1606955174906
},
"gatherer": "psi",
"errors": []
}
]
}
実行すると tests.recurring.nextTriggerTimestamp
が現在時刻 + 1 日に更新される
これは tests.recurring.frequency
が Daily
に設定されているため、次の実行日時をテスト実行時の + 1日に更新したのだと思われる
↓実行後
{
"tests": [
{
"label": "web.dev",
"url": "https://web.dev",
"recurring": {
"frequency": "Daily",
"nextTriggerTimestamp": 1610267063035
},
"gatherer": "psi",
"errors": []
}
]
}
更新後もう一度同じコマンドを実行しても、テストは実行されない
これはたぶん現在時刻が tests.recurring.nextTriggerTimestamp
より前の日だからだと思われる
実行
準備はつまるところ、tests.recurring.nextTriggerTimestamp
を更新しているので手動で書き換えても良い
./awp continue examples/tests-recurring.json output/results.json
tests.recurring.nextTriggerTimestamp
を1分後などにして動作テストしていたのだが実行されなかった
理由は、どうやら 10 分毎に実行するかチェックをしているっぽいので、動作テストをする場合は10分待つ必要がある
async continue(options) {
options = options || {};
options.recurring = true;
let self = this;
let isRunning = false;
// Set timer interval as every 10 mins by default.
let timerInterval = options.timerInterval ?
parseInt(options.timerInterval) : 60 * 10;
if (options.verbose) {
this.log(`Timer interval sets as ${timerInterval} seconds.`);
}
await self.recurring(options);
// Run contiuously.
return await new Promise(resolve => {
const interval = setInterval(async () => {
if (isRunning) return;
await self.recurring(options);
await self.retrieve(options);
isRunning = false;
if (options.verbose) {
self.log('Waiting for next timer triggered...');
}
}, timerInterval * 1000);
});
}
無事10分待って定期的な実行を確認 👍
スプレッドシートへの書き込み
手順1 サービスアカウントの作成
すでにサービスアカウントがある場合はスキップ
編集者権限が必要なので、作成時につける
Google Sheets API を有効化しておく
手順2 スプレッドシートの作成
公式からサンプルが提供されているのでこれを参考に作成する
Tests
タブと、Results
タブを作成
Resuts
は空で、Tests
にはせっかくなので自分が運営しているサイトと、比較のために web.dev
を指定
シートを先程作ったサービスアカウントに共有する
service-account.json
の作成
手順3 サービスアカウントの詳細画面の「鍵を追加」から作る
AutoWebPerf
では tmp
が .gitignore
に追加されているので、tmp
ディレクトリ配下に置いておく
手順4 Chrome UX Report API キーの作成
Chrome UX Report API を有効化しておく
キーはデフォルトで作られる
手順5 実行
https://docs.google.com/spreadsheets/d/1c3k9eEVg12Atoa72tglVVBg--o0CEMkOF3JCaLlxzeo/edit
MY GOOGLE SHEET ID
は↑の URL であれば 1c3k9eEVg12Atoa72tglVVBg--o0CEMkOF3JCaLlxzeo
になる
SERVICE_ACCOUNT_CREDENTIALS=./tmp/service-account.json CRUX_APIKEY=MY_API_KEY ./awp run sheets:[MY GOOGLE SHEET ID]/Tests sheets:[MY GOOGLE SHEET ID]/Results
成功したが、自分のサイトはデータがなかった(悲しい)
DataStudio での可視化
CrUX API
テンプレートが用意されているのでこちらを元に作っていきます
「テンプレートを使用」をクリックし、「新しいデータソース」→「新しいデータソースの作成」
先程作ったスプレッドシートの Results
を選択します
「レポートに追加」
「レポートをコピー」で作成します
良い感じにグラフが表示されました!
Firebase Functions で定期実行
課金は必須ですが、Cloud Scheduler の各ジョブのコストは月額 $0.10(USD)であり、Google アカウントごとに 3 つのジョブを無料で使用できるため、全体的なコストは管理可能であることが期待できます
3つまでは無料とのこと
実装
コード上で利用する場合 README とは引数が少し違う
tests
, results
はコマンドラインからの実行と同じように connector
と path
を定義する
環境変数は envVars
経由で渡す必要がある
SERVICE_ACCOUNT_CREDENTIALS
の取得に少し工夫しています
import * as admin from "firebase-admin";
const AutoWebPerf = require('awp/src/awp-core');
admin.initializeApp();
const bucket = admin.storage().bucket();
const SHEET_ID = 'XXX';
const SERVICE_ACCOUNT_CREDENTIALS_FILE_NAME = 'service-account.json';
const LOCAL_SERVICE_ACCOUNT_CREDENTIALS_PATH = `/tmp/${SERVICE_ACCOUNT_CREDENTIALS_FILE_NAME}`;
const SERVICE_ACCOUNT_CREDENTIALS_PATH = `..${LOCAL_SERVICE_ACCOUNT_CREDENTIALS_PATH}`;
const CRUX_APIKEY = 'XXX';
export async function run() {
await bucket.file(SERVICE_ACCOUNT_CREDENTIALS_FILE_NAME).download({
destination: LOCAL_SERVICE_ACCOUNT_CREDENTIALS_PATH
});
const awp = new AutoWebPerf({
"tests": {
"connector": "sheets",
"path": `${SHEET_ID}/Tests`
},
"results": {
"connector": "sheets",
"path": `${SHEET_ID}/Results`
},
"envVars": {
"SERVICE_ACCOUNT_CREDENTIALS": SERVICE_ACCOUNT_CREDENTIALS_PATH,
"CRUX_APIKEY": CRUX_APIKEY
}
});
awp.run();
}
import * as functions from 'firebase-functions';
import { run } from './awp';
export const scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(() => {
run();
return null;
});
デプロイ
最初ロケーションを設定していなかったのでビルド時にエラーになった
Error: Cloud resource location is not set for this project but scheduled functions requires it. Please see this documentation for more details: https://firebase.google.com/docs/projects/locations.