fix: completely sever client bundle from backend logger (pino) and validation (zod) to eliminate 68 KiB unused JS
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🧪 QA (push) Successful in 1m43s
Build & Deploy / 🏗️ Build (push) Successful in 3m23s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🔔 Notify (push) Successful in 3s
All checks were successful
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🚀 Deploy (push) Successful in 34s
Build & Deploy / 🧪 QA (push) Successful in 1m43s
Build & Deploy / 🏗️ Build (push) Successful in 3m23s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 1m12s
Build & Deploy / 🔔 Notify (push) Successful in 3s
This commit is contained in:
@@ -26,9 +26,7 @@ export default function Error({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const services = getAppServices();
|
console.error('Application error caught by boundary', {
|
||||||
services.errors.captureException(error);
|
|
||||||
services.logger.error('Application error caught by boundary', {
|
|
||||||
message: error?.message || 'Unknown error',
|
message: error?.message || 'Unknown error',
|
||||||
stack: error?.stack,
|
stack: error?.stack,
|
||||||
digest: error?.digest,
|
digest: error?.digest,
|
||||||
|
|||||||
@@ -2,34 +2,28 @@
|
|||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { usePathname, useSearchParams } from 'next/navigation';
|
import { usePathname, useSearchParams } from 'next/navigation';
|
||||||
import { getAppServices } from '@/lib/services/create-services';
|
import { useAnalytics } from './useAnalytics';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AnalyticsProvider Component
|
* AnalyticsProvider Component
|
||||||
*
|
*
|
||||||
* Automatically tracks pageviews on client-side route changes.
|
* Automatically tracks pageviews on client-side route changes.
|
||||||
* This component handles navigation events for the Umami analytics service.
|
* This component handles navigation events for the Umami analytics service.
|
||||||
*
|
|
||||||
* Note: Website ID is now centrally managed on the server side via a proxy,
|
|
||||||
* so it's no longer needed as a prop here.
|
|
||||||
*/
|
*/
|
||||||
export default function AnalyticsProvider() {
|
export default function AnalyticsProvider() {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const { trackPageview } = useAnalytics();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pathname) return;
|
if (!pathname) return;
|
||||||
|
|
||||||
const services = getAppServices();
|
|
||||||
const url = `${pathname}${searchParams?.size ? `?${searchParams.toString()}` : ''}`;
|
const url = `${pathname}${searchParams?.size ? `?${searchParams.toString()}` : ''}`;
|
||||||
|
|
||||||
// Track pageview with the full URL
|
// Track pageview with the full URL
|
||||||
// The service will relay this to our internal proxy which injects the Website ID
|
// The service will relay this to our internal proxy which injects the Website ID
|
||||||
services.analytics.trackPageview(url);
|
trackPageview(url);
|
||||||
|
}, [pathname, searchParams, trackPageview]);
|
||||||
// Services like logger are already sub-initialized in getAppServices()
|
|
||||||
// so we don't need to log here manually.
|
|
||||||
}, [pathname, searchParams]);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +1,69 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { getAppServices } from '@/lib/services/create-services';
|
|
||||||
import type { AnalyticsEventProperties } from '@/lib/services/analytics/analytics-service';
|
export type AnalyticsEventProperties = Record<string, any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a payload to the proxy API without loading backend config/logger dependencies.
|
||||||
|
*/
|
||||||
|
function sendAnalyticsPayload(type: 'event', data: Record<string, any>) {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
if (process.env.NEXT_PUBLIC_CI === 'true') return;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
hostname: window.location.hostname,
|
||||||
|
screen: `${window.screen.width}x${window.screen.height}`,
|
||||||
|
language: navigator.language,
|
||||||
|
referrer: document.referrer,
|
||||||
|
title: document.title,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
fetch('/stats/api/send', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ type, payload }),
|
||||||
|
keepalive: true,
|
||||||
|
}).catch(e => console.error('[Umami] Failed to send payload', e));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Umami] Error sending analytics', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook for tracking analytics events with Umami.
|
* Custom hook for tracking analytics events with Umami.
|
||||||
*
|
|
||||||
* Provides a convenient way to track custom events throughout your application.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* import { useAnalytics } from '@/components/analytics/useAnalytics';
|
|
||||||
*
|
|
||||||
* function MyComponent() {
|
|
||||||
* const { trackEvent, trackPageview } = useAnalytics();
|
|
||||||
*
|
|
||||||
* const handleButtonClick = () => {
|
|
||||||
* trackEvent('button_click', {
|
|
||||||
* button_id: 'cta-primary',
|
|
||||||
* page: 'homepage'
|
|
||||||
* });
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* return <button onClick={handleButtonClick}>Click me</button>;
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```tsx
|
|
||||||
* // Track a custom pageview
|
|
||||||
* const { trackPageview } = useAnalytics();
|
|
||||||
* trackPageview('/custom-path?param=value');
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
export function useAnalytics() {
|
export function useAnalytics() {
|
||||||
const services = getAppServices();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Track a custom event with optional properties.
|
|
||||||
*
|
|
||||||
* @param eventName - The name of the event to track
|
|
||||||
* @param properties - Optional event properties (metadata)
|
|
||||||
*/
|
|
||||||
const trackEvent = useCallback(
|
const trackEvent = useCallback(
|
||||||
(eventName: string, properties?: AnalyticsEventProperties) => {
|
(eventName: string, properties?: AnalyticsEventProperties) => {
|
||||||
services.analytics.track(eventName, properties);
|
sendAnalyticsPayload('event', {
|
||||||
|
name: eventName,
|
||||||
|
data: properties,
|
||||||
|
url: window.location.pathname + window.location.search,
|
||||||
|
});
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log('[Umami] Tracked event:', eventName, properties);
|
console.log('[Umami] Tracked event:', eventName, properties);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[services]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Track a pageview (useful for custom navigation or SPA routing).
|
|
||||||
*
|
|
||||||
* @param url - The URL to track (defaults to current location)
|
|
||||||
*/
|
|
||||||
const trackPageview = useCallback(
|
const trackPageview = useCallback(
|
||||||
(url?: string) => {
|
(url?: string) => {
|
||||||
services.analytics.trackPageview(url);
|
sendAnalyticsPayload('event', {
|
||||||
|
url: url || window.location.pathname + window.location.search,
|
||||||
|
});
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log('[Umami] Tracked pageview:', url ?? 'current location');
|
console.log('[Umami] Tracked pageview:', url ?? 'current location');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[services]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preinstall": "npx only-allow pnpm"
|
"preinstall": "npx only-allow pnpm"
|
||||||
},
|
},
|
||||||
"version": "2.2.89",
|
"version": "2.2.90",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"@parcel/watcher",
|
"@parcel/watcher",
|
||||||
|
|||||||
Reference in New Issue
Block a user