JamStackでもアクセスカウンターを実装したい

2021年12月13日(月) 3時21分10秒 | 312 view |

この記事はmicroCMS Advent Calendar 2021 17日目の記事です。
https://qiita.com/advent-calendar/2021/microcms
皆さんの記事を見ていて自分も知らなかったMicroCMSの機能や使い方をしれたので、Advent Calendarはとても好きです。
個人的には@Ryusouさんの1日目の記事で、MicroCMSダッシュボードが知らない間にアップデートされていたことを知れたのが良かったです。



後はPOST入稿の際にリッチテキストをもうちょっとなんとかできると個人的に嬉しいなあ。。。

閑話休題。
今回はJAMStackブログにアクセスカウンターを実装する方法について紹介します。

作ったもの

このブログもすでに実装済みなんですが、デプロイされるたびにPV数をGoogle Analyticsから取得し、掲載するようなものです。

非同期ですが、毎週自動更新でもかけておけば1週間に一度はPV数が更新されるので、ないよりはマシかなと思います。ページビュー数ランキングとかも実装できるので幅が広がりそうですね。

実は一ヶ月前ころにすでに実装していたんですが、その際はphpでサーバーを書いていた作り方でした
https://utautattaro.blog/post/0t4o770032u

ですが今回はnodejsで書き直しができたので、そちらの方法を紹介します。nodejsで書けるのでビルドプロセスにそのまま組み込むことができます。

技術スタック

  • Nuxt.js v2
  • Google Analytics Reporting API v4
  • googleapis - npm
  • MicroCMS patch API


作り方

まずは上記の記事に従ってAPIの登録、鍵ファイルの保存、MicroCMSでpvカラム追加まで終わらせてください。

次にGoogle APIs Node.js Clientのインストールを行います。結構重たいです。

npm install googleapis


インストールが完了したら、ダッシュボードから保存した鍵ファイルをnuxt.config.jsと同じ階層にホストします
ファイル名はservice-account-credentials.jsonとします。

次にnuxt.config.jsを書き換えます

import { google } from 'googleapis'
export default {
  generate: {
    async routes () {
     //auth Clientの作成
     const client = await google.auth.getClient({
      keyFile: './service-account-credentials.json', // キー JSON ファイルを配置した場所を指定する
      scopes: 'https://www.googleapis.com/auth/analytics.readonly',
     })
   
     //Reporting API v4の使用準備
     const analyticsreporting = await google.analyticsreporting({
      version: 'v4',
      auth: client,
     })

     //レポーティングデータ取得
     const res = await analyticsreporting.reports.batchGet({
      requestBody: {
       reportRequests: [
        {
         viewId: 'xxxxxxxx', // ビュー ID を指定する
         dateRanges: [
          {
           startDate: '2020-09-01',
           endDate: 'today',
          },
         ],
         metrics: [{ expression: 'ga:pageviews' }],
         dimensions: [{ name: 'ga:pagePath' }],
         dimensionFilterClauses: [{
          filters : [{
           "dimensionName": 'ga:pagePath',
           "operator": 'PARTIAL',
           "expressions": [
            'post'
           ],
          }]
         }],
        },
       ],
      },
     })
     let gaOutput = res.data.reports[0].data.rows;
   
     let pvobj = {};

     //パスの正規化とPV数集計
     for(let obj in gaOutput){
      let url = new URL("https://utautattaro.blog" + gaOutput[obj].dimensions[0]);
      let path = url.pathname;
      if(path.slice(-1) != "/"){
       path += "/";
      }
       
      if(pvobj[path]){
       pvobj[path].paveview += parseInt(gaOutput[obj].metrics[0].values[0],10);
      }else{
       pvobj[path] = {
        path : path,
        id : path.slice(6).slice(0,-1),
        pageview : parseInt(gaOutput[obj].metrics[0].values[0],10)
       }
      }
     }

     //MicroCMSへ送信
     for(let pv in pvobj){
      try {
       console.log("try : " + pvobj[pv].id);
       await axios.patch('https://yourdomain.microcms.io/api/v1/yourendpoint/'+pvobj[pv].id,{"pv":pvobj[pv].pageview},{headers: { "X-MICROCMS-API-KEY": "env.microcmsapikey","Content-Type":"application/json" }})
      } catch (e) {
       console.log(e)
      }
      console.log("done");
     }
    }
  }
}


これでpv数がMicroCMS側にビルド時に保管され、ブログ内で利用することができるようになります。

解説

auth Clientの作成、Reporting API v4の使用準備

特にひねりなくサンプル通り記述します。

レポーティングデータ取得

ビューIDを指定し、取得範囲を設定します。
今回は累計データが必要だったので、startDateはブログ開始日、enddateは今日にしています。これで累計PV数が取得可能です。
metricsdimensionsはそれぞれga:pageviews, ga:pagePathを指定します。ページタイトルがほしい方はdimensionsに追加してみてください。
今回は記事データのPV数がほしいので、Filterで検索範囲を絞っています。このブログの設計上、記事ページは/post/_postidというパススキームであるため、expressionspostという文字列をpagePathから部分一致で取得しています。

パスの正規化とPV数集計

今回はPV数集計が目的ですが、同一ページでもパスの違いでGoogle Analyticsでは別集計となることがあるため、正規化を行いページビュー数を合算しています。
例えば、/post/hoge//post/hoge/post/hoge?query=fuga はすべて同一ページですがGoogle Analytics上では別集計となってしまいます。
JavaScriptには便利なURLクラスがあるので、取得されたページを片っ端からURLクラスでinitして、pathnameで一致したものを単一として集計します。
また扱いやすいようにpathnameがkeyとなった連想配列に追加します。

MicroCMSへ送信

最後にMicroCMSへPATCHで送信し修正します。削除された記事などもPV数としては残っているため、PATCHをした際に400エラーでプロセスが止まってしまうことを避けるためtry catchを利用しています。

以上でNuxtのビルドプロセス内でアクセスカウンターを実装できました。PHPでは外部にPHPが動くサーバーとAPIが必要でしたが、ビルドに組み込まれているのでCIでビルドしたタイミングで更新されるためこちらのほうが使いやすそうです。

最後に

最後に@RyusouさんよりmicroCMSの「推し」機能もぜひ教えてください!とのことだったので紹介します。
自分の推し機能はズバリMicroCMSに同梱されたimgixです!

imgix、便利な画像CDNですが、個人的に使い始めるまでハードルが高い気がしていて、いつもimagekit.ioなど別の画像CDNを利用しています。
MicroCMSではそれが画像をアップロードした瞬間からすべての機能が使えるという大盤振る舞いで、しかもMicroCMSとimgixで契約をしているとのことなので安心です。

自分はこれで画像修正をしたり、記事のOGPとして利用したりしています。
https://utautattaro.blog/post/r1ykn-8n0

来年1月にプラン内容も大幅に変わるようで、ますます楽しみですね。
無料で複数人が使えるのも大変嬉しいです。リッチテキストPOST入稿もお願いします🙇