diff --git a/.changeset/sentry-client-entry.md b/.changeset/sentry-client-entry.md new file mode 100644 index 000000000..8c4ef13f5 --- /dev/null +++ b/.changeset/sentry-client-entry.md @@ -0,0 +1,5 @@ +--- +"@workspace/web": patch +--- + +Sentry now initializes in a dedicated client entry before hydration, so client errors thrown during early module evaluation are captured. The router-aware browser-tracing integration is attached separately once the router exists. diff --git a/apps/web/src/client.tsx b/apps/web/src/client.tsx new file mode 100644 index 000000000..0e353b965 --- /dev/null +++ b/apps/web/src/client.tsx @@ -0,0 +1,30 @@ +import * as Sentry from "@sentry/tanstackstart-react"; +import { StartClient } from "@tanstack/react-start/client"; +import { StrictMode, startTransition } from "react"; +import { hydrateRoot } from "react-dom/client"; + +// Initialize Sentry here, in the client entry, before hydration — so telemetry +// emitted during module evaluation (e.g. a third-party lib that throws at import +// time) is captured. The router-aware browser-tracing integration needs the +// router instance, so it's attached separately in router.tsx via +// Sentry.addIntegration once the router exists. See issue #320. +// +// The hydration below mirrors TanStack Start's default client entry for our +// version; defining this file overrides that default. +if (import.meta.env.VITE_SENTRY_DSN) { + Sentry.init({ + dsn: import.meta.env.VITE_SENTRY_DSN, + environment: import.meta.env.MODE, + sendDefaultPii: true, + tracesSampleRate: 1.0, + }); +} + +startTransition(() => { + hydrateRoot( + document, + + + , + ); +}); diff --git a/apps/web/src/router.tsx b/apps/web/src/router.tsx index 6a78883e5..683822cf8 100644 --- a/apps/web/src/router.tsx +++ b/apps/web/src/router.tsx @@ -26,14 +26,11 @@ export const getRouter = () => { defaultStaleTime: 30_000, // Cache loader data for 30s to avoid re-fetching on navigations }); + // Sentry.init() runs in the client entry (client.tsx) before hydration; here + // we only attach the router-aware browser-tracing integration, which needs + // the router instance that doesn't exist yet at client-entry time. See #320. if (!router.isServer && import.meta.env.VITE_SENTRY_DSN) { - Sentry.init({ - dsn: import.meta.env.VITE_SENTRY_DSN, - environment: import.meta.env.MODE, - sendDefaultPii: true, - integrations: [Sentry.tanstackRouterBrowserTracingIntegration(router)], - tracesSampleRate: 1.0, - }); + Sentry.addIntegration(Sentry.tanstackRouterBrowserTracingIntegration(router)); } setupRouterSsrQueryIntegration({ router, queryClient: rqContext.queryClient });