SpreadSheetからPageSpeed InsightsAPIを呼び出す（GAS）

## PageSpeedInsights
最近Webアプリケーションでパフォーマンスが求められることが多いと思います。その時にどのように画面のパフォーマンス測定しようかと思った時に、調べて出てきたツールです。

画面のパフォーマンスの測定だけではなく、様々なWebに関する主な指標が表示されます。
![スクリーンショット 2023-09-04 23.19.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296562/0671fb97-54dd-394e-9bc9-a6bda55fc207.png)

## Largest Contentful Paint(LCP)
>the time a website takes to show the user the largest content on the screen, complete and ready for interaction.
Google defines that this metric considers only the content above the page’s fold, meaning everything that appears without scrolling.

Web サイトが画面上に完成してインタラクションの準備ができた最大のコンテンツをユーザーに表示するまでにかかる時間。
Google は、この指標ではページのスクロールせずに見えるコンテンツのみを考慮すると定義しています。つまり、スクロールせずに表示されるすべてのコンテンツを意味します。

つまり、URLを表示した際に最初に写るコンテンツをうつす時間と言えそうです。
一般的な測定ではこちらの指標を使うと良いのかもしれません。

試しに阿部寛のHPで測ってみました。
http://abehiroshi.la.coocan.jp/
![スクリーンショット 2023-09-04 23.48.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296562/d827b1bb-1936-191b-109f-763f9e46d0f7.png)
めちゃくちゃ爆速ですね。

## First Input Delay(FID)
>FID measures the time from when a user first interacts with a page (that is, when they click a link, tap on a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to begin processing event handlers in response to that interaction.
FID は、ユーザーが最初にページを操作したとき (つまり、リンクをクリックしたとき、ボタンをタップしたとき、または JavaScript ベースのカスタム コントロールを使用したとき) からブラウザが実際に処理を開始できるようになるまでの時間を測定します。 

こちらはURLが実際に表示されてから何かを操作してブラウザが処理を開始できるまでの時間ですね。こちらも早ければより良いと思われます。


## Comulative Layout Shift(CLS)
>Cumulative Layout Shift (累積レイアウト シフト数、CLS) は、視覚的な安定性を測定するための重要なユーザーを中心とした指標です。これは、ユーザーが予期しないレイアウト シフトに遭遇する頻度の数値化に役立つ指標であり、CLS が低ければ低いほど、そのページが快適であることが保証されます。

https://web.dev/i18n/ja/cls/
こちらは少し難しい概念ですが、視覚的な安定性があるページほど値が低くなるみたいです。
## First Contentful(FCP)
>FCP（First Contentful Paint）とは、ユーザーがURLをクリックしてから、サイトがレンダリングを開始する（データを読み込んでブラウザで表示を開始する）までの時間を指します。

FCPは秒数で表し、速度の分類については、0～1 秒未満の場合は「高速」、1以上～2.5 秒の場合は「平均」、2.5 秒以上の場合は「低速」とされています。
Largest Contentful Paint(LCP)の前に測定される概念だと思われるので、この値が遅ければLCPも遅くなると思われます。


## Interaction to Next Paint(INP)
>Interaction to Next Paint (INP) is a metric that makes up the Google Search Console Core Web Vitals report for evaluating the user experience on a page. The INP measures the time between one interaction and another that the user made on the page, and will indicate the longest interaction.

Interaction to Next Paint (INP) は、ページ上のユーザー エクスペリエンスを評価するための Google Search Console Core Web Vitals レポートを構成する指標です。 INP は、ユーザーがページ上で行った 1 つのインタラクションと別のインタラクションの間の時間を測定し、最長のインタラクションを示します。

こちらはインタラクションとインタラクションの間のブロック時間を測定するようです。
つまりボタンを押してから次のアクションが起こるまでの時間が長ければ、ユーザからするとボタンを押しても何も起こらないな？と思ってしまうので、この時間はできる限り少ない方がいいですね。
https://web.dev/inp/

## Time to First Byte(TTFB)
>TTFBとは「最初の1バイトを受信するまでの時間」（Time To First Byte）を意味します。TTFBはブラウザがサーバーからのデータの最初の1バイトを受け取るまでにかかる時間のことです。このデータを受け取るまでに時間がかかるほど、ページの表示が遅くなります。よくある誤解が、DNSルックアップ後にTTFBが計算されるというもの。しかし、実際のネットワークにおけるTTFBの計算には常にネットワークレイテンシが含まれます。これは3つのステップで構成され、その間のどこでも遅延やレイテンシが発生する可能性があり、結果として合計TTFBが累積していきます。

https://kinsta.com/jp/blog/ttfb/
こちらに関しては様々な議論がされているようですが、重要な指標で良好なスコアを獲得する能力を妨げない限り、サイトが「良好な」TTFBしきい値を満たすことが絶対に必要というわけではないようです。シングルページアプリケーション (SPA) の場合のように、Web サイトが最初のマークアップを迅速に配信するものの、その後そのマークアップに意味のあるコンテンツを追加するために JavaScript が必要になる場合は、可能な限り低い TTFB を達成することが特に重要です。 

とのことです。つまり最初にマークアップを受け取る時間が早ければ、SPAなどのシングルページアプリケーションにおいてレンダリングが早くなる可能性があるとのことです。

## SpreadSheetでPageSpeedInsightsを呼び出す
今回は、パフォーマンスを図りたいURLを測定した結果をスプレッドシートに自動で反映するツールを作成したいと思います。
測定対象となるURL（変数）を増やした際は、同様に測定するようにします。
新しく測定した場合、列を増やすようにします（あとで比較できるように）

## GASの設定
まずGASの設定をします。Appscriptを起動したら準備OKです。

## GASで関数を実行する
```javascript

function runLighthouseForUrlsWithPerformanceAndHeaders() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = sheet.getRange("A:A").getValues(); // A列からURLを取得

  // Lighthouse APIのエンドポイントURL
  var apiUrl = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=";
  var category = "performance"; // カテゴリを performance に指定

  var requests = [];

  // A1にURLのヘッダーを追加
  sheet.getRange(1, 1).setValue("URL");

  for (var i = 0; i < data.length; i++) {
    var url = data[i][0]; // A列からURLを取得

    // URLが空でない場合にAPIリクエストを追加
    if (url) {
      var apiRequestUrl = apiUrl + encodeURIComponent(url) + "&category=" + category;

      // Lighthouse APIリクエストを追加
      var options = {
        "method": "GET",
        "muteHttpExceptions": true
      };

      requests.push({url: apiRequestUrl, options: options});
    }
  }

  // 一括でAPIリクエストを送信
  var responses = UrlFetchApp.fetchAll(requests);

  // ヘッダーを追加（Performance Scoreの列が存在しない場合）
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  if (headers.indexOf("Performance Score") === -1) {
    sheet.getRange(1, headers.length + 1).setValue("Performance Score"); // 新しいヘッダーを追加
  }

  // レスポンスを処理してスプレッドシートに書き込む
  for (var i = 0; i < responses.length; i++) {
    var response = responses[i];
    var jsonResponse = response.getContentText();
    var lighthouseData = JSON.parse(jsonResponse);
    var performanceScore = lighthouseData.lighthouseResult.categories.performance.score;

    // データをスプレッドシートに書き込む（Performance Scoreを新たに追加）
    var rowIndex = i + 2;
    sheet.getRange(rowIndex, headers.length + 1).setValue(performanceScore); // パフォーマンススコアを新しい列に追加
  }
}


```

![スクリーンショット 2023-09-05 6.51.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296562/4400b46f-147f-5ccf-eb3d-5ebe2e9b4f2a.png)

なかなかいい感じにできました。トリガーを設定したらデイリーとか1時間ごとにパフォーマンスをとってくれると思います。
各シートごとに分けたりして下記の測定値でURLをしらべてみると色々発見があるかもしれません。
各基準となる値があるので色付けしたら面白いかもしれません。

Largest Contentful Paint(LCP)
First Input Delay(FID)
Comulative Layout Shift(CLS)
First Contentful(FCP)
Interaction to Next Paint(INP)
Time to First Byte(TTFB)

レスポンスの値などは、下記に記載されてます。
https://developers.google.com/speed/docs/insights/v5/reference/pagespeedapi/runpagespeed?hl=ja#response