Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(remix): Wrap root with ErrorBoundary. #5365

Merged
merged 6 commits into from
Jul 8, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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