参考リンク
- umami Docs
- umami releases
- doc Vite- 環境変数とモード
- Vite アプリケーションに環境変数を参照させる
- doc Vite- Vite設定ファイル 共通オプション
- Vueの環境変数が設定できず悩んだ件(vite使用)
- doc vuepress- Passing Data to Client Code
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
.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 は「定数」にのみ使用することをおすすめします。
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 i axios
Routerメソッドの "afterEach()" で ページ遷移ごとに Umami API へPV情報を axios でPOST
Routerメソッドの "afterEach()" で ページ遷移ごとに Umami API へPV情報を axios でPOSTする処理を記述
// 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通信される

