Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 8 additions & 168 deletions packages/react-router/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,176 +10,16 @@
[![npm dm](https://img.shields.io/npm/dm/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router)
[![npm dt](https://img.shields.io/npm/dt/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router)

> This SDK is for [React Router (framework)](https://reactrouter.com/start/framework/installation). If you're using [React Router (library)](https://reactrouter.com/start/library/installation) see our
> [React SDK here](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/).
The official Sentry SDK for monitoring React Router applications in framework mode.

## Links
For React Router in library mode, use the [React SDK](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/).

- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/react-router/)
## Documentation

## General
- [Getting started](https://docs.sentry.io/platforms/javascript/guides/react-router/)
- [Configuration](https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/)

This package is a wrapper around `@sentry/node` for the server and `@sentry/browser` for the client side.
## Support

## Manual Setup

### Expose Hooks

React Router exposes two hooks in your `app` folder (`entry.client.tsx` and `entry.server.tsx`).
If you do not see these two files, expose them with the following command:

```bash
npx react-router reveal
```

### Client-Side Setup

Initialize the SDK in your `entry.client.tsx` file:

```tsx
import * as Sentry from '@sentry/react-router';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';
import { HydratedRouter } from 'react-router/dom';

Sentry.init({
dsn: '___PUBLIC_DSN___',
integrations: [Sentry.reactRouterTracingIntegration()],

tracesSampleRate: 1.0, // Capture 100% of the transactions

// Set `tracePropagationTargets` to declare which URL(s) should have trace propagation enabled
tracePropagationTargets: [/^\//, /^https:\/\/yourserver\.io\/api/],
});

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<HydratedRouter instrumentations={[Sentry.createSentryClientInstrumentation()]} onError={Sentry.sentryOnError} />
</StrictMode>,
);
});
```

Now, update your `app/root.tsx` file to report any unhandled errors from your global error boundary:

```tsx
import * as Sentry from '@sentry/react-router';

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = 'Oops!';
let details = 'An unexpected error occurred.';
let stack: string | undefined;

if (isRouteErrorResponse(error)) {
message = error.status === 404 ? '404' : 'Error';
details = error.status === 404 ? 'The requested page could not be found.' : error.statusText || details;
} else if (error && error instanceof Error) {
// you only want to capture non 404-errors that reach the boundary
Sentry.captureException(error);
if (import.meta.env.DEV) {
details = error.message;
stack = error.stack;
}
}

return (
<main>
<h1>{message}</h1>
<p>{details}</p>
{stack && (
<pre>
<code>{stack}</code>
</pre>
)}
</main>
);
}
// ...
```

### Server-Side Setup

Create an `instrument.server.mjs` file in the root of your app:

```js
import * as Sentry from '@sentry/react-router';

Sentry.init({
dsn: '___PUBLIC_DSN___',
tracesSampleRate: 1.0, // Capture 100% of the transactions
});
```

In your `entry.server.tsx` file, import the instrumentation file at the very top, export the
`instrumentations` array, and export the `handleError` function:

```tsx
import './instrument.server.mjs';
import * as Sentry from '@sentry/react-router';
import { type HandleErrorFunction } from 'react-router';

export const handleError: HandleErrorFunction = (error, { request }) => {
// React Router may abort some interrupted requests, report those
if (!request.signal.aborted) {
Sentry.captureException(error);

// make sure to still log the error so you can see it
console.error(error);
}
};

// Register the Sentry server instrumentation so loaders, actions and middleware are traced.
export const instrumentations = [Sentry.createSentryServerInstrumentation()];
// ... rest of your server entry
```

### Loading the Instrumentation via `--import` (Alternative)

Instead of importing the instrumentation file at the top of `entry.server.tsx`, you can load it before
the application starts via the `--import` command line option. Since React Router runs in ESM mode,
update the `start` and `dev` scripts accordingly:

```json
"scripts": {
"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev",
"start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js",
}
```

## Build-time Config

Update your vite.config.ts file to include the `sentryReactRouter` plugin and also add your config options to the vite config (this is required for uploading sourcemaps at the end of the build):

```ts
import { reactRouter } from '@react-router/dev/vite';
import { sentryReactRouter } from '@sentry/react-router/vite';
import { defineConfig } from 'vite';

const sentryConfig = {
authToken: '...',
org: '...',
project: '...',
// rest of your config
};

export default defineConfig(config => {
return {
plugins: [reactRouter(), sentryReactRouter(sentryConfig, config)],
sentryConfig,
};
});
```

Next, in your `react-router.config.ts` file, include the `sentryOnBuildEnd` hook:

```ts
import type { Config } from '@react-router/dev/config';
import { sentryOnBuildEnd } from '@sentry/react-router/vite';

export default {
ssr: true,
buildEnd: sentryOnBuildEnd,
} satisfies Config;
```
- [Report a bug](https://github.com/getsentry/sentry-javascript/issues/new/choose)
- [Contributing](https://github.com/getsentry/sentry-javascript/blob/develop/CONTRIBUTING.md)
Loading