VuePress に Umami アナリティクスをセットアップ

vuePress 公開日: 2022-04-28 更新: 2022-05-20
サムネ画像

参考リンク

head に umami scriptタグを設置(※重複したデータ送信を行う)

// docs/.vuepress/config.ts

export default defineUserConfig({
  // === site config メタデータ ===
  title: 'VuePress v2 DEMO',
  lang: 'ja',
  description: 'Just playing around',
  head: [
    // umami アナリティクス https://umami.is/docs/tracker-config
    // 参考 https://web-ninja21.com/press/ja/articles/vuepress/2022-02-09-avoid-embedding.html
    ['script',{
      async: true,
      defer: true, // ページの読み込みが完了した時点で実行
      "data-website-id": 'abcdefg-xxxxx-xxxxx-xxxxxxx',
      "data-domains": 'vuepress-demo-rho.vercel.app', // 本番環境 ドメインのみカウント
      "data-auto-track": 'true', // false = デフォルトのトラッキングデータ自動送信をOFF
      src: 'https://xxxxxxxxxx/umami.js',
      crossorigin: "anonymous", // window.onerrorでエラー詳細を取得するためのもの https://qiita.com/asmsuechan/items/70c4b6f56139034738c2
      }
    ],
  ],
})

注意

config.ts の head オプションに、umami 埋め込み scriptタグを追加して試したが、重複したデータのPOST通信を行うことが確認できた為、却下

define オプションを使ってビルド時にアプリ内から参照可能なグローバル定数を生成

doc- Development Hooks / define open in new window

.env ファイルを用意して読み込みを試みたがうまく行かなかった為、config.ts で define オプションを使ってビルド時にアプリ内から参照可能なグローバル定数を生成

// docs/.vuepress/config.ts
import { defineUserConfig } from 'vuepress-vite'
// ...

export default defineUserConfig({
  // ...

  // === Development Hooks === https://v2.vuepress.vuejs.org/reference/plugin-api.html#development-hooks
  // ビルド時にアプリ内から参照可能なグローバル定数を生成
  define: {
    ENV_API_KEY: JSON.stringify('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx'),
  },

  // === Lifecycle Hooks === https://v2.vuepress.vuejs.org/reference/plugin-api.html#lifecycle-hooks
  // ...
});

文字列を定義する場合 JSON.stringify() を使う

2.0.0-beta.70 以降、文字列の値は純粋な式として評価されるので、文字列の定数を定義する場合は、明示的に引用符で囲う必要があります(例 JSON.stringify を使う)

マッチした部分が単語の境界(\b)で囲まれている場合のみ置換されます。

構文解析なしの単純なテキスト置換として実装されているため、define は「定数」にのみ使用することをおすすめします。

doc- Vite defineopen in new window

console.log("🚀 ~ file: ~ JSON.parse(ENV_API_KEY)", JSON.parse(ENV_API_KEY));
// 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx'

クライアント 拡張ファイル "clientAppEnhance.ts" ファイルを追加

DANGER

v2.0.0-beta.44 で、.vuepress/clientAppEnhance.{js,ts} は .vuepress/client.{js,ts} にリネームされ、使い方も変更

クライアント 拡張ファイル "clientAppEnhance.ts" ファイルを追加し、 ページ遷移ごとに Umami へPV情報をPOSTする処理を追加

POST通信用に axios モジュールをインポート

npm- axiosopen in new window

npm i axios

Routerメソッドの "afterEach()" で ページ遷移ごとに Umami API へPV情報を axios でPOST

Routerメソッドの "afterEach()" で ページ遷移ごとに Umami API へPV情報を axios でPOSTする処理を記述

umami APIopen in new window

// docs/.vuepress/clientAppEnhance.ts

// 設定ファイルで clientAppEnhanceFiles を明示的に設定しない限り、.vuepress/clientAppEnhance.{js,ts}ファイルが暗黙的にクライアントアプリの拡張ファイルとして使用される
import { defineClientAppEnhance } from '@vuepress/client'
import axios from 'axios' // axios をインポート

export default defineClientAppEnhance(({ app, router, siteData }) => {
  // Router Methods ~ beforeEach & afterEach ~ https://router.vuejs.org/api/#router-methods
  router.afterEach((to, from) => {
    // console.log('after navigation')
    if (to.path !== from.path) { // ページリロードなどのアクセスを除外
      // umami アナリティクスへPV送信
      const postData = {
        "payload": {
          // "website": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx", // umami トラッキングコードより取得
          "website": JSON.parse(ENV_API_KEY), // config.ts の define: で設定したグローバル変数より取得(コードはumami トラッキングコードより取得できる)
          "url": window.location.pathname,
          "referrer": from.fullPath.split('#')[0].split('.html')[0], // .html#xyz~ は不要なので除外
          "hostname": window.location.hostname,
          "language": window.navigator.language,
          "screen": `${window.innerWidth}x${window.innerHeight}`,
        },
        "type": "pageview"
      };
      // development 開発環境時のみ
      if (import.meta.env.DEV) { // vite では process = undefined
        console.log("🚀 ~ file: clientAppEnhance.ts ~ line 37 ~ router.afterEach ~ development 開発環境❗");
        console.log("🚀 ~ file: clientAppEnhance.ts ~ line 30 ~ router.afterEach ~ postData👈👈: ", postData);
      };
      // Production 本番環境のみ
      if (import.meta.env.PROD) {
        // axios で、 umami APIへ PVデータをPOST
        const apiUrl = "https://umamianalyze.vercel.app/api/collect";
        axios.post(apiUrl, postData);
      };
    }
  });
});

ビルドエラー

開発環境では問題ないが、ビルドを実行すると "ReferenceError: window is not defined" となる

[代替策] スクリプト コンポーネントを追加し、onMountedフックでページ遷移ごとにAPIへPOST通信

POST送信する PVデータObj の型エイリアス (type alias) を追加

// docs/.vuepress/type.ts
// ...
// umami アナリティクスへPOST送信する PVデータObj の型
export type PostPV = {
  "payload": {
    "website": string, // config.ts の define: で設定したグローバル変数より取得(コードはumami トラッキングコードより取得できる)
    "url": string,
    "referrer": string, // .html#xyz~ は不要なので除外
    "hostname": string,
    "language": string,
    "screen": string,
  },
  "type": "pageview"
};

umami APIへ PV情報をPOST送信する関数を追加

// docs/.vuepress/func/methods.ts
import { AppPageData, PageData, ArticleData, PostPV } from '../type' // 型エイリアス (type alias)
// ...

// axios で Umami APIへ PV をPOST
export const postPVtoUmami = (pvObj: PostPV) => {
  const apiUrl: string = 'https://UMAMI-APP-URL/api/collect'
  // axios で、 umami APIへ PVデータをPOST
  axios.post(apiUrl, pvObj);
};

スクリプトコンポーネント ”UmamiPostPV.vue” を追加し、子テーマの拡張ファイルとして読み込み

// docs/.vuepress/components/UmamiPostPV.vue

<!-- 各ページ移動時に UmamiへPVをPOSTする コンポーネント -->
<script setup lang="ts">
import { onMounted } from 'vue'
import { PostPV } from '../type' // 型エイリアス (type alias)
// メソッド
import { postPVtoUmami } from '../func/methods'


const umamiSiteID: string = JSON.parse(ENV_API_KEY);
const currentPath: string = window.history.state.current
let referrer: string = document.referrer
if (window.history.state.back) {
  referrer = `${window.location.origin}${window.history.state.back}`
}
// console.log("🚀 ~ file: UmamiPostPV.vue ~ line 14 ~ referrer🌟🌟", referrer);

// umami アナリティクスへPOST送信するPVデータObj
const postData: PostPV = {
  "payload": {
    "website": umamiSiteID, // config.ts の define: で設定したグローバル変数より取得(コードはumami トラッキングコードより取得できる)
    "url": currentPath,
    "referrer": referrer,
    "hostname": window.location.hostname,
    "language": window.navigator.language,
    "screen": `${window.innerWidth}x${window.innerHeight}`,
  },
  "type": "pageview"
};


onMounted(() => {
  // development 開発環境時のみ
  if (import.meta.env.DEV) { // vite では process = undefined
    console.log("🚀 ~ file: UmamiPostPV.vue ~ line 57 ~ onMounted ~ development 開発環境❗");
    console.log("🚀 ~ file: UmamiPostPV.vue ~ line 50 ~ onMounted ~ postData👈👈: ", postData);
  }
  // Production 本番環境のみ
  else if (import.meta.env.PROD) {
    // axios で、 umami APIへ PVデータをPOST
    postPVtoUmami(postData);
  };
})
</script>

<template>
</template>

子テーマファイル に スクリプトコンポーネントを追加

// docs/.vuepress/theme/layouts/Layout.vue

// https://github.com/vuepress/vuepress-next/blob/main/packages/%40vuepress/theme-default/src/client/layouts/Layout.vue
// デフォルトテーマのLayoutで提供されるスロットを利用して拡張
<script setup>
import ParentLayout from '@vuepress/theme-default/lib/client/layouts/Layout.vue'
</script>

<template>
  <ParentLayout>

    <!-- サイドバーTOPにカスタムコンポーネントを追加 -->
    <template #sidebar-top>
      <CustomSidebarTop />
    </template>

    <!-- 各ページ下部に カスタム フッターコンポーネントを追加 -->
    <template #page-bottom>
      <CustomPageFooter />
      <UmamiPostPV />
    </template>

  </ParentLayout>
</template>



















 




これで、本番環境のみ 各ページ遷移ごとにUmami APIへ PVデータがPOST通信される

My Custom Footer

Join 31,000+ other and never miss out

About

Company

Blog

Tec

Contact

example@email.com

© Brand 2020 - All rights reserved