Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default withSentryConfig(nextConfig, {
// For all available options, see:
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
org: "100kode",
project: "javascript-nextjs",
project: "vibe-coding-profiler",

// Only print logs for uploading source maps in CI
silent: !process.env.CI,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"vite": "^7",
"vitest": "^3"
"vitest": "^3.2.6"
}
}
38 changes: 19 additions & 19 deletions apps/web/src/components/PlausibleProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { Suspense, useEffect, useRef } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import { init, track } from "@plausible-analytics/tracker";

/**
* Inner component that uses useSearchParams (requires Suspense boundary).
Expand All @@ -11,6 +10,7 @@ function PlausibleTracker() {
const pathname = usePathname();
const searchParams = useSearchParams();
const isInitialized = useRef(false);
const initialization = useRef<Promise<void> | null>(null);

// Initialize Plausible once
useEffect(() => {
Expand All @@ -23,27 +23,24 @@ function PlausibleTracker() {
return;
}

if (!isInitialized.current) {
init({
domain,
// Don't track localhost unless explicitly enabled
captureOnLocalhost: process.env.NEXT_PUBLIC_PLAUSIBLE_CAPTURE_LOCALHOST === "true",
// Track outbound link clicks
outboundLinks: true,
// Track file downloads
fileDownloads: true,
// Track form submissions
formSubmissions: true,
// Disable auto capture - we handle it manually for Next.js App Router
autoCapturePageviews: false,
});
isInitialized.current = true;
}
initialization.current = import("@plausible-analytics/tracker").then(({ init }) => {
if (!isInitialized.current) {
init({
domain,
captureOnLocalhost: process.env.NEXT_PUBLIC_PLAUSIBLE_CAPTURE_LOCALHOST === "true",
outboundLinks: true,
fileDownloads: true,
formSubmissions: true,
autoCapturePageviews: false,
});
isInitialized.current = true;
}
});
}, []);

// Track page views on route changes
useEffect(() => {
if (!process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN || !isInitialized.current) {
if (!process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN || !initialization.current) {
return;
}

Expand All @@ -53,7 +50,10 @@ function PlausibleTracker() {
: pathname;

// Track pageview with the current URL
track("pageview", { url });
void initialization.current.then(async () => {
const { track } = await import("@plausible-analytics/tracker");
track("pageview", { url });
});
}, [pathname, searchParams]);

return null;
Expand Down
8 changes: 8 additions & 0 deletions apps/web/src/lib/__tests__/analytics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { describe, expect, it } from "vitest";

describe("analytics modules", () => {
it("can load during server rendering without browser globals", async () => {
await expect(import("../analytics")).resolves.toBeDefined();
await expect(import("../../components/PlausibleProvider")).resolves.toBeDefined();
});
});
16 changes: 10 additions & 6 deletions apps/web/src/lib/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { track } from "@plausible-analytics/tracker";

/**
* Track a custom event in Plausible Analytics.
*
Expand All @@ -20,10 +18,16 @@ export function trackEvent(
return;
}

track(eventName, {
props,
interactive: options?.interactive,
revenue: options?.revenue,
if (typeof window === "undefined") {
return;
}

void import("@plausible-analytics/tracker").then(({ track }) => {
track(eventName, {
props,
interactive: options?.interactive,
revenue: options?.revenue,
});
});
}

Expand Down
4 changes: 4 additions & 0 deletions apps/web/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export default defineConfig({
resolve: {
alias: {
"@": resolve(__dirname, "./src"),
"@plausible-analytics/tracker": resolve(
__dirname,
"../../node_modules/@plausible-analytics/tracker/plausible.js"
),
},
},
});
Loading
Loading