From 2b6638e1607e5c44eb6f6dc987e9e893927f1829 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:51:23 +0900 Subject: feat: google analytics (#15451) * wip backend * wip frontend * build misskey-js * implement control panel * fix * introduce analytics wrapper * spdx * Update analytics.ts * Update common.ts * wip * wip * wip * wip * wip * Update CHANGELOG.md --------- Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> --- packages/frontend/src/analytics.ts | 107 +++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 packages/frontend/src/analytics.ts (limited to 'packages/frontend/src/analytics.ts') diff --git a/packages/frontend/src/analytics.ts b/packages/frontend/src/analytics.ts new file mode 100644 index 0000000000..e07a4e9258 --- /dev/null +++ b/packages/frontend/src/analytics.ts @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as Misskey from 'misskey-js'; +import type { AnalyticsInstance, AnalyticsPlugin } from 'analytics'; + +/** + * analytics moduleを読み込まなくても動作するようにするためのラッパー + */ +class AnalyticsProxy implements AnalyticsInstance { + private analytics?: AnalyticsInstance; + + constructor(analytics?: AnalyticsInstance) { + if (analytics) { + this.analytics = analytics; + } + } + + public setAnalytics(analytics: AnalyticsInstance) { + if (this.analytics) { + throw new Error('Analytics instance already exists.'); + } + this.analytics = analytics; + } + + public identify(...args: Parameters) { + return this.analytics?.identify(...args) ?? Promise.resolve(); + } + + public track(...args: Parameters) { + return this.analytics?.track(...args) ?? Promise.resolve(); + } + + public page(...args: Parameters) { + return this.analytics?.page(...args) ?? Promise.resolve(); + } + + public user(...args: Parameters) { + return this.analytics?.user(...args) ?? Promise.resolve(); + } + + public reset(...args: Parameters) { + return this.analytics?.reset(...args) ?? Promise.resolve(); + } + + public ready(...args: Parameters) { + return this.analytics?.ready(...args) ?? function () { void 0; }; + } + + public on(...args: Parameters) { + return this.analytics?.on(...args) ?? function () { void 0; }; + } + + public once(...args: Parameters) { + return this.analytics?.once(...args) ?? function () { void 0; }; + } + + public getState(...args: Parameters) { + return this.analytics?.getState(...args) ?? Promise.resolve(); + } + + public get storage() { + return this.analytics?.storage ?? { + getItem: () => null, + setItem: () => void 0, + removeItem: () => void 0, + }; + } + + public get plugins() { + return this.analytics?.plugins ?? { + enable: (p, c) => Promise.resolve(c ? c() : void 0), + disable: (p, c) => Promise.resolve(c ? c() : void 0), + }; + } +} + +export const analytics = new AnalyticsProxy(); + +export async function initAnalytics(instance: Misskey.entities.MetaDetailed) { + // アナリティクスプロバイダに関する設定がひとつもない場合は、アナリティクスモジュールを読み込まない + if (!instance.googleAnalyticsMeasurementId) { + return; + } + + const { default: Analytics } = await import('analytics'); + const plugins: AnalyticsPlugin[] = []; + + // Google Analytics + if (instance.googleAnalyticsMeasurementId) { + const { default: googleAnalytics } = await import('@analytics/google-analytics'); + + plugins.push(googleAnalytics({ + measurementIds: [instance.googleAnalyticsMeasurementId], + debug: _DEV_, + })); + } + + analytics.setAnalytics(Analytics({ + app: 'misskey', + version: _VERSION_, + debug: _DEV_, + plugins, + })); +} -- cgit v1.2.3-freya