Skip to content

Commit

Permalink
feat(remix): Wrap root with ErrorBoundary. (#5365)
Browse files Browse the repository at this point in the history
Wraps the Remix root with `ErrorBoundary` while wrapping it with the router instrumentation.
  • Loading branch information
onurtemizkan authored Jul 8, 2022
1 parent 3e7a3ec commit ae086f9
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 21 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export * from '@sentry/browser';

export { init } from './sdk';
export { Profiler, withProfiler, useProfiler } from './profiler';
export type { FallbackRender } from './errorboundary';
export type { ErrorBoundaryProps, FallbackRender } from './errorboundary';
export { ErrorBoundary, withErrorBoundary } from './errorboundary';
export { createReduxEnhancer } from './redux';
export { reactRouterV3Instrumentation } from './reactrouterv3';
Expand Down
49 changes: 32 additions & 17 deletions packages/remix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Sentry.init({
});
```

Also, wrap your Remix root, with Sentry's `ErrorBoundary` component to catch React component errors, and `withSentryRouteTracing` to get parameterized router transactions.
Also, wrap your Remix root with `withSentry` to catch React component errors and to get parameterized router transactions.

```ts
// root.tsx
Expand All @@ -71,28 +71,43 @@ import {
ScrollRestoration,
} from "@remix-run/react";

import { ErrorBoundary, withSentryRouteTracing } from "@sentry/remix";
import { withSentry } from "@sentry/remix";

function App() {
return (
<ErrorBoundary>
<html>
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
</ErrorBoundary>
<html>
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

export default withSentryRouteTracing(App);
export default withSentry(App);
```

You can disable or configure `ErrorBoundary` using a second parameter to `withSentry`.

```ts

withSentry(App, {
wrapWithErrorBoundary: false
});

// or

withSentry(App, {
errorBoundaryOptions: {
fallback: <p>An error has occurred</p>
}
});
```

To set context information or send manual events, use the exported functions of `@sentry/remix`.
Expand Down
2 changes: 1 addition & 1 deletion packages/remix/src/index.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { configureScope, init as reactInit, Integrations } from '@sentry/react';

import { buildMetadata } from './utils/metadata';
import { RemixOptions } from './utils/remixOptions';
export { remixRouterInstrumentation, withSentryRouteTracing } from './performance/client';
export { remixRouterInstrumentation, withSentry } from './performance/client';
export { BrowserTracing } from '@sentry/tracing';
export * from '@sentry/react';

Expand Down
2 changes: 1 addition & 1 deletion packages/remix/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { buildMetadata } from './utils/metadata';
import { RemixOptions } from './utils/remixOptions';

export { ErrorBoundary, withErrorBoundary } from '@sentry/react';
export { remixRouterInstrumentation, withSentryRouteTracing } from './performance/client';
export { remixRouterInstrumentation, withSentry } from './performance/client';
export { BrowserTracing, Integrations } from '@sentry/tracing';
export * from '@sentry/node';

Expand Down
24 changes: 23 additions & 1 deletion packages/remix/src/performance/client.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ErrorBoundaryProps } from '@sentry/react';
import { withErrorBoundary } from '@sentry/react';
import { Transaction, TransactionContext } from '@sentry/types';
import { getGlobalObject, logger } from '@sentry/utils';
import * as React from 'react';
Expand Down Expand Up @@ -79,8 +81,21 @@ export function remixRouterInstrumentation(useEffect: UseEffect, useLocation: Us
/**
* Wraps a remix `root` (see: https://remix.run/docs/en/v1/guides/migrating-react-router-app#creating-the-root-route)
* To enable pageload/navigation tracing on every route.
* Also wraps the application with `ErrorBoundary`.
*
* @param OrigApp The Remix root to wrap
* @param options The options for ErrorBoundary wrapper.
*/
export function withSentryRouteTracing<P extends Record<string, unknown>, R extends React.FC<P>>(OrigApp: R): R {
export function withSentry<P extends Record<string, unknown>, R extends React.FC<P>>(
OrigApp: R,
options: {
wrapWithErrorBoundary?: boolean;
errorBoundaryOptions?: ErrorBoundaryProps;
} = {
wrapWithErrorBoundary: true,
errorBoundaryOptions: {},
},
): R {
const SentryRoot: React.FC<P> = (props: P) => {
// Early return when any of the required functions is not available.
if (!_useEffect || !_useLocation || !_useMatches || !_customStartTransaction) {
Expand All @@ -91,6 +106,7 @@ export function withSentryRouteTracing<P extends Record<string, unknown>, R exte
// will break advanced type inference done by react router params
return <OrigApp {...props} />;
}

let isBaseLocation: boolean = false;

const location = _useLocation();
Expand Down Expand Up @@ -133,6 +149,12 @@ export function withSentryRouteTracing<P extends Record<string, unknown>, R exte
return <OrigApp {...props} />;
};

if (options.wrapWithErrorBoundary) {
// @ts-ignore Setting more specific React Component typing for `R` generic above
// will break advanced type inference done by react router params
return withErrorBoundary(SentryRoot, options.errorBoundaryOptions);
}

// @ts-ignore Setting more specific React Component typing for `R` generic above
// will break advanced type inference done by react router params
return SentryRoot;
Expand Down

0 comments on commit ae086f9

Please sign in to comment.