fix: add posthog error monitor

This commit is contained in:
David Nguyen
2025-02-25 15:14:45 +11:00
parent cedd5e87b1
commit 7e8955b89c
17 changed files with 175 additions and 148 deletions

View File

@ -3,10 +3,12 @@ import { useCallback, useEffect } from 'react';
import { useRevalidator } from 'react-router';
export const RefreshOnFocus = () => {
const { revalidate } = useRevalidator();
const { revalidate, state } = useRevalidator();
const onFocus = useCallback(() => {
void revalidate();
if (state === 'idle') {
void revalidate();
}
}, [revalidate]);
useEffect(() => {

View File

@ -1,21 +1,30 @@
import { StrictMode, startTransition } from 'react';
import { StrictMode, startTransition, useEffect } from 'react';
import { i18n } from '@lingui/core';
import { detect, fromHtmlTag } from '@lingui/detect-locale';
import { I18nProvider } from '@lingui/react';
import posthog from 'posthog-js';
import { hydrateRoot } from 'react-dom/client';
import { HydratedRouter } from 'react-router/dom';
import { Theme, ThemeProvider } from 'remix-themes';
import { match } from 'ts-pattern';
import { extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
import { dynamicActivate } from '@documenso/lib/utils/i18n';
async function main() {
const theme = match(document.documentElement.getAttribute('data-theme'))
.with('dark', () => Theme.DARK)
.with('light', () => Theme.LIGHT)
.otherwise(() => null);
function PosthogInit() {
const postHogConfig = extractPostHogConfig();
useEffect(() => {
if (postHogConfig) {
posthog.init(postHogConfig.key, {
api_host: postHogConfig.host,
});
}
}, []);
return null;
}
async function main() {
const locale = detect(fromHtmlTag('lang')) || 'en';
await dynamicActivate(locale);
@ -25,10 +34,10 @@ async function main() {
document,
<StrictMode>
<I18nProvider i18n={i18n}>
<ThemeProvider specifiedTheme={theme} themeAction="/api/theme">
<HydratedRouter />
</ThemeProvider>
<HydratedRouter />
</I18nProvider>
<PosthogInit />
</StrictMode>,
);
});

View File

@ -7,13 +7,11 @@ import type { RenderToPipeableStreamOptions } from 'react-dom/server';
import { renderToPipeableStream } from 'react-dom/server';
import type { AppLoadContext, EntryContext } from 'react-router';
import { ServerRouter } from 'react-router';
import { ThemeProvider } from 'remix-themes';
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
import { dynamicActivate, extractLocaleData } from '@documenso/lib/utils/i18n';
import { langCookie } from './storage/lang-cookie.server';
import { themeSessionResolver } from './storage/theme-session.server';
export const streamTimeout = 5_000;
@ -32,10 +30,6 @@ export default async function handleRequest(
await dynamicActivate(language);
const { getTheme } = await themeSessionResolver(request);
const theme = getTheme();
return new Promise((resolve, reject) => {
let shellRendered = false;
const userAgent = request.headers.get('user-agent');
@ -47,9 +41,7 @@ export default async function handleRequest(
const { pipe, abort } = renderToPipeableStream(
<I18nProvider i18n={i18n}>
<ThemeProvider specifiedTheme={theme} themeAction="/api/theme">
<ServerRouter context={routerContext} url={request.url} />
</ThemeProvider>
<ServerRouter context={routerContext} url={request.url} />
</I18nProvider>,
{
[readyOption]() {

View File

@ -1,47 +0,0 @@
import { useEffect } from 'react';
import posthog from 'posthog-js';
import { useLocation, useSearchParams } from 'react-router';
import { extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
export function PostHogPageview() {
const postHogConfig = extractPostHogConfig();
const { pathname } = useLocation();
const [searchParams] = useSearchParams();
// const { sessionData } = useOptionalSession();
// const user = sessionData?.user;
if (typeof window !== 'undefined' && postHogConfig) {
posthog.init(postHogConfig.key, {
api_host: postHogConfig.host,
disable_session_recording: true,
// loaded: () => {
// if (user) {
// posthog.identify(user.email ?? user.id.toString());
// } else {
// posthog.reset();
// }
// },
custom_campaign_params: ['src'],
});
}
useEffect(() => {
if (!postHogConfig || !pathname) {
return;
}
let url = window.origin + pathname;
if (searchParams && searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', {
$current_url: url,
});
}, [pathname, searchParams, postHogConfig]);
return null;
}

View File

@ -1,4 +1,4 @@
import { Suspense, useEffect } from 'react';
import { useEffect } from 'react';
import Plausible from 'plausible-tracker';
import {
@ -12,7 +12,7 @@ import {
useLoaderData,
useLocation,
} from 'react-router';
import { PreventFlashOnWrongTheme, useTheme } from 'remix-themes';
import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from 'remix-themes';
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
import { SessionProvider } from '@documenso/lib/client-only/providers/session';
@ -28,7 +28,6 @@ import type { Route } from './+types/root';
import stylesheet from './app.css?url';
import { GenericErrorLayout } from './components/general/generic-error-layout';
import { RefreshOnFocus } from './components/general/refresh-on-focus';
import { PostHogPageview } from './providers/posthog';
import { langCookie } from './storage/lang-cookie.server';
import { themeSessionResolver } from './storage/theme-session.server';
import { appMetaTags } from './utils/meta';
@ -106,9 +105,7 @@ export async function loader({ request }: Route.LoaderArgs) {
}
export function Layout({ children }: { children: React.ReactNode }) {
const { publicEnv, lang, session, ...data } = useLoaderData<typeof loader>() || {};
const [theme] = useTheme();
const { theme } = useLoaderData<typeof loader>() || {};
const location = useLocation();
@ -118,6 +115,18 @@ export function Layout({ children }: { children: React.ReactNode }) {
}
}, [location.pathname]);
return (
<ThemeProvider specifiedTheme={theme} themeAction="/api/theme">
<LayoutContent>{children}</LayoutContent>
</ThemeProvider>
);
}
export function LayoutContent({ children }: { children: React.ReactNode }) {
const { publicEnv, session, lang, ...data } = useLoaderData<typeof loader>() || {};
const [theme] = useTheme();
return (
<html translate="no" lang={lang} data-theme={theme} className={theme ?? ''}>
<head>
@ -133,10 +142,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
<meta name="google" content="notranslate" />
<PreventFlashOnWrongTheme ssrTheme={Boolean(data.theme)} />
<Suspense>
<PostHogPageview />
</Suspense>
{/* Fix: https://stackoverflow.com/questions/21147149/flash-of-unstyled-content-fouc-in-firefox-only-is-ff-slow-renderer */}
<script>0</script>
</head>

View File

@ -23,6 +23,8 @@ const posthogProxy = async (request: Request) => {
method: request.method,
headers,
body: request.body,
// @ts-expect-error - Not really sure about this
duplex: 'half',
});
return new Response(response.body, {