Skip to content

Commit 57c9237

Browse files
authored
Merge pull request #146 from codediodeio/analytics
analytics: PageView component
2 parents 80af67a + e01bf79 commit 57c9237

File tree

16 files changed

+185
-23
lines changed

16 files changed

+185
-23
lines changed

README.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A minimal, yet powerful library that puts realtime Firebase data into Svelte stores.
44

5-
[Documentation](https://sveltefire.fireship.io)
5+
[Full Documentation](https://sveltefire.fireship.io)
66

77
```svelte
88
<!-- 1. 🔥 Firebase App -->
@@ -22,17 +22,6 @@ A minimal, yet powerful library that puts realtime Firebase data into Svelte sto
2222
<Collection ref={postRef.path + '/comments'} let:data={comments}>
2323
{#each comments as comment}
2424
25-
{/each}
26-
27-
<!-- 3 (b). 📜 Get a Realtime Database node owned by a user -->
28-
<Node path={`posts/${user.uid}`} let:data={post} let:ref={postRef}>
29-
30-
<h2>{post.title}</h2>
31-
32-
<!-- 4 (b). 💬 Get all the comments in its subnodes -->
33-
<NodeList path={postRef.path + '/comments'} let:data={comments}>
34-
{#each comments as comment}
35-
3625
{/each}
3726
...
3827
```
@@ -46,6 +35,7 @@ Svelte makes it possible to dramatically simplify the way developers work with F
4635
- Better TypeScript experience for Firebase
4736
- Handle complex relational data between Auth, Firestore, and Realtime Database
4837
- Easily hydrate SvelteKit server data into a realtime Firebase stream
38+
- Simple Google Analytics integration for SvelteKit
4939

5040
## Quick Start
5141

@@ -60,12 +50,14 @@ import { initializeApp } from "firebase/app";
6050
import { getFirestore } from "firebase/firestore";
6151
import { getDatabase } from "firebase/database";
6252
import { getAuth } from "firebase/auth";
53+
import { getAnalytics } from "firebase/analytics";
6354

6455
// Initialize Firebase
6556
const app = initializeApp(/* your firebase config */);
6657
export const db = getFirestore(app);
6758
export const rtdb = getDatabase(app);
6859
export const auth = getAuth(app);
60+
export const auth = getAnalytics(app);
6961
```
7062

7163
2. Get the Current user
@@ -98,6 +90,24 @@ Use the `$` as much as you want - it will only result in one Firebase read reque
9890

9991
Or better yet, use the built in `Doc` and `Collection` components for Firestore, or `Node` and `NodeList` components for Realtime Database. See below.
10092

93+
4. Add Firebase/Google Analytics
94+
95+
Easily generate a `page_view` event on every route change with SvelteKit layouts - works for both client and server rendered pages.
96+
97+
```svelte
98+
<!-- +layout.svelte -->
99+
<script lang="ts">
100+
import { page } from "$app/stores";
101+
import { PageView } from "sveltefire";
102+
</script>
103+
104+
<slot />
105+
106+
{#key $page.route.id}
107+
<PageView />
108+
{/key}
109+
```
110+
101111
## Stores
102112

103113
Stores are the building blocks of SvelteFire.

docs/src/components/SideNav.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<li><a href="/rtdb/node-component">&ltNode&gt</a></li>
2828
<li><a href="/rtdb/node-list-component">&ltNodeList&gt</a></li>
2929
<li class="heading">analytics</li>
30-
<li><a href="/guide/todo">&ltPageView&gt</a></li>
30+
<li><a href="/analytics/page-view-component">&ltPageView&gt</a></li>
3131
</ul>
3232
</nav>
3333

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
title: PageView Component
3+
pubDate: 2023-12-23
4+
description: SvelteFire PageView Component API reference
5+
layout: ../../layouts/MainLayout.astro
6+
---
7+
8+
# PageView
9+
10+
The `PageView` component logs a Google analytics `page_view` event when it is mounted.
11+
12+
### Slot Props
13+
14+
- `eventName` - (default: 'page_view') Set the current user as the userId in Google Analytics
15+
- `setUser` - (default: true) Set the current user as the userId in Google Analytics
16+
- `customParams` - (optional) custom parameters to pass to the `signIn` function
17+
18+
### Layout Example (recommended)
19+
20+
The most efficient way to integrate Firebase Analytics is to log events from a layout component. This will ensure that every route change is logged, both on the client and server. Make sure to `key` the `PageView` component so that it is re-mounted on every route change.
21+
22+
```svelte
23+
<!-- +layout.svelte -->
24+
<script lang="ts">
25+
import { page } from "$app/stores";
26+
import { PageView } from "sveltefire";
27+
</script>
28+
29+
<slot />
30+
31+
{#key $page.route.id}
32+
<PageView />
33+
{/key}
34+
```
35+
36+
### Page Example
37+
38+
For fine-grained control, you can include `PageView` on a page-by-page basis. This is useful when sending custom parameters.
39+
40+
41+
```svelte
42+
<!-- +page.svelte -->
43+
<script lang="ts">
44+
const myData = {
45+
guild: 'griffindor',
46+
currency: 'gpb'
47+
}
48+
</script>
49+
50+
51+
<PageView eventName="my_page_view" customParams={myData} setUser={false} />
52+
```

src/lib/components/FirebaseApp.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
import type { Firestore } from "firebase/firestore";
55
import type { Database } from "firebase/database";
66
import type { FirebaseStorage } from "firebase/storage";
7+
import type { Analytics } from "firebase/analytics";
78
89
export let firestore: Firestore;
910
export let rtdb: Database;
1011
export let auth: Auth;
1112
export let storage: FirebaseStorage;
13+
export let analytics: Analytics | null;
1214
13-
setFirebaseContext({ firestore, rtdb, auth, storage });
15+
setFirebaseContext({ firestore, rtdb, auth, storage, analytics });
1416
</script>
1517

1618
<slot />

src/lib/components/PageView.svelte

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script lang="ts">
2+
import { logEvent, setUserId, isSupported } from "firebase/analytics";
3+
import { getFirebaseContext } from "$lib/index.js";
4+
import { onMount } from "svelte";
5+
6+
export let eventName = "page_view";
7+
export let setUser = true;
8+
export let customParams: Record<string, unknown> = {};
9+
10+
const analytics = getFirebaseContext().analytics!;
11+
const auth = getFirebaseContext().auth!;
12+
13+
onMount(async () => {
14+
if (!(await isSupported())) {
15+
return;
16+
}
17+
if (setUser) {
18+
setUserId(analytics, auth.currentUser?.uid ?? null);
19+
}
20+
logEvent(analytics, eventName, {
21+
page_location: window.location.href,
22+
page_path: window.location.pathname,
23+
page_title: document.title,
24+
...customParams,
25+
});
26+
});
27+
</script>

src/lib/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import SignedOut from './components/SignedOut.svelte';
88
import DownloadURL from './components/DownloadURL.svelte';
99
import StorageList from './components/StorageList.svelte';
1010
import UploadTask from './components/UploadTask.svelte';
11-
import { userStore } from './stores/auth.js';
12-
import { docStore, collectionStore } from './stores/firestore.js';
13-
import { nodeStore, nodeListStore } from './stores/rtdb.js';
14-
import { getFirebaseContext } from './stores/sdk.js';
15-
import { downloadUrlStore, storageListStore, uploadTaskStore } from './stores/storage.js';
11+
import PageView from './components/PageView.svelte';
12+
import { userStore } from './stores/auth';
13+
import { docStore, collectionStore } from './stores/firestore';
14+
import { nodeStore, nodeListStore } from './stores/rtdb';
15+
import { getFirebaseContext } from './stores/sdk';
16+
import { downloadUrlStore, storageListStore, uploadTaskStore } from './stores/storage';
1617

1718
export {
1819
Doc,
@@ -24,6 +25,7 @@ export {
2425
UploadTask,
2526
StorageList,
2627
DownloadURL,
28+
PageView,
2729
downloadUrlStore,
2830
storageListStore,
2931
uploadTaskStore,

src/lib/stores/auth.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { writable } from "svelte/store";
2-
import { getFirebaseContext } from "./sdk.js";
32
import { onAuthStateChanged, type Auth } from "firebase/auth";
43

54
/**

src/lib/stores/sdk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import type { Database } from "firebase/database";
33
import type { Auth } from "firebase/auth";
44
import { getContext, setContext } from "svelte";
55
import type { FirebaseStorage } from "firebase/storage";
6+
import type { Analytics } from "firebase/analytics";
67

78
export interface FirebaseSDKContext {
89
auth?: Auth;
910
firestore?: Firestore;
1011
rtdb?: Database;
1112
storage?: FirebaseStorage;
13+
analytics?: Analytics | null;
1214
}
1315

1416
export const contextKey = "firebase";

src/routes/+layout.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import FirebaseApp from "$lib/components/FirebaseApp.svelte";
3-
import { db as firestore, auth, rtdb, storage } from "./firebase.js";
3+
import { db as firestore, auth, rtdb, storage, analytics } from "./firebase.js";
44
</script>
55

6-
<FirebaseApp {auth} {firestore} {rtdb} {storage}>
6+
<FirebaseApp {auth} {firestore} {rtdb} {storage} {analytics}>
77
<slot />
88
</FirebaseApp>

src/routes/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<li><a href="/rtdb-test">Realtime Database Test</a></li>
1313
<li><a href="/ssr-test">SSR Test</a></li>
1414
<li><a href="/storage-test">Storage Test</a></li>
15+
<li><a href="/analytics-test">Analytics Test</a></li>
1516
</ul>
1617
<ul>
1718
<li data-testid="auth">Auth Context: {!!ctx.auth}</li>

0 commit comments

Comments
 (0)