Skip to content

Commit 5c04b8d

Browse files
committed
Switch to AST parsing, keep server component manually instrumented
1 parent 3e46675 commit 5c04b8d

30 files changed

Lines changed: 1220 additions & 2087 deletions

dev-packages/e2e-tests/test-applications/react-router-7-rsc/app/routes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ export default [
1010
route('server-component-redirect', 'routes/rsc/server-component-redirect.tsx'),
1111
route('server-component-not-found', 'routes/rsc/server-component-not-found.tsx'),
1212
route('server-component/:param', 'routes/rsc/server-component-param.tsx'),
13+
route('server-component-comment-directive', 'routes/rsc/server-component-comment-directive.tsx'),
1314
// RSC Server Function tests
1415
route('server-function', 'routes/rsc/server-function.tsx'),
1516
route('server-function-error', 'routes/rsc/server-function-error.tsx'),
17+
route('server-function-arrow', 'routes/rsc/server-function-arrow.tsx'),
18+
route('server-function-default', 'routes/rsc/server-function-default.tsx'),
1619
]),
1720
...prefix('performance', [
1821
index('routes/performance/index.tsx'),
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
'use server';
2+
3+
// This file only has a default export — the Sentry plugin should wrap it as
4+
// a default server function, NOT extract "defaultAction" as a named export.
5+
export default async function defaultAction(formData: FormData): Promise<{ success: boolean; message: string }> {
6+
const name = formData.get('name') as string;
7+
await new Promise(resolve => setTimeout(resolve, 50));
8+
return {
9+
success: true,
10+
message: `Default: Hello, ${name}!`,
11+
};
12+
}
Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
'use server';
22

3-
import { wrapServerFunction } from '@sentry/react-router';
4-
5-
async function _submitForm(formData: FormData): Promise<{ success: boolean; message: string }> {
3+
export async function submitForm(formData: FormData): Promise<{ success: boolean; message: string }> {
64
const name = formData.get('name') as string;
75

86
// Simulate some async work
@@ -14,22 +12,16 @@ async function _submitForm(formData: FormData): Promise<{ success: boolean; mess
1412
};
1513
}
1614

17-
export const submitForm = wrapServerFunction('submitForm', _submitForm);
18-
19-
async function _submitFormWithError(_formData: FormData): Promise<{ success: boolean; message: string }> {
15+
export async function submitFormWithError(_formData: FormData): Promise<{ success: boolean; message: string }> {
2016
// Simulate an error in server function
2117
throw new Error('RSC Server Function Error: Something went wrong!');
2218
}
2319

24-
export const submitFormWithError = wrapServerFunction('submitFormWithError', _submitFormWithError);
25-
26-
async function _getData(): Promise<{ timestamp: number; data: string }> {
27-
await new Promise(resolve => setTimeout(resolve, 20));
28-
20+
export const submitFormArrow = async (formData: FormData): Promise<{ success: boolean; message: string }> => {
21+
const name = formData.get('name') as string;
22+
await new Promise(resolve => setTimeout(resolve, 50));
2923
return {
30-
timestamp: Date.now(),
31-
data: 'Fetched from server function',
24+
success: true,
25+
message: `Arrow: Hello, ${name}!`,
3226
};
33-
}
34-
35-
export const getData = wrapServerFunction('getData', _getData);
27+
};

dev-packages/e2e-tests/test-applications/react-router-7-rsc/app/routes/rsc/server-component-async.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { wrapServerComponent } from '@sentry/react-router';
12
import type { Route } from './+types/server-component-async';
23

34
async function fetchData(): Promise<{ title: string; content: string }> {
@@ -8,7 +9,7 @@ async function fetchData(): Promise<{ title: string; content: string }> {
89
};
910
}
1011

11-
export default async function AsyncServerComponent(_props: Route.ComponentProps) {
12+
async function AsyncServerComponent(_props: Route.ComponentProps) {
1213
const data = await fetchData();
1314

1415
return (
@@ -19,6 +20,11 @@ export default async function AsyncServerComponent(_props: Route.ComponentProps)
1920
);
2021
}
2122

23+
export default wrapServerComponent(AsyncServerComponent, {
24+
componentRoute: '/rsc/server-component-async',
25+
componentType: 'Page',
26+
});
27+
2228
export async function loader() {
2329
const data = await fetchData();
2430
return data;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// This is a server component, NOT a client component.
2+
// "use client" — this comment should be ignored by the Sentry plugin.
3+
4+
import { wrapServerComponent } from '@sentry/react-router';
5+
import type { Route } from './+types/server-component-comment-directive';
6+
7+
async function ServerComponentWithCommentDirective({ loaderData }: Route.ComponentProps) {
8+
await new Promise(resolve => setTimeout(resolve, 10));
9+
10+
return (
11+
<main>
12+
<h1 data-testid="title">Server Component With Comment Directive</h1>
13+
<p data-testid="loader-message">Message: {loaderData?.message ?? 'No loader data'}</p>
14+
</main>
15+
);
16+
}
17+
18+
export default wrapServerComponent(ServerComponentWithCommentDirective, {
19+
componentRoute: '/rsc/server-component-comment-directive',
20+
componentType: 'Page',
21+
});
22+
23+
export async function loader() {
24+
return { message: 'Hello from comment-directive server component!' };
25+
}
Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
11
import { wrapServerComponent } from '@sentry/react-router';
2-
import type { Route } from './+types/server-component-error';
32

4-
// Demonstrate error capture in wrapServerComponent
5-
async function _ServerComponentWithError(_props: Route.ComponentProps) {
3+
async function ServerComponentWithError() {
64
throw new Error('RSC Server Component Error: Mamma mia!');
75
}
86

9-
const ServerComponent = wrapServerComponent(_ServerComponentWithError, {
7+
export default wrapServerComponent(ServerComponentWithError, {
108
componentRoute: '/rsc/server-component-error',
119
componentType: 'Page',
1210
});
13-
14-
// For testing, we can trigger the wrapped component via a loader
15-
export async function loader() {
16-
// Call the wrapped ServerComponent to test error capture
17-
try {
18-
await ServerComponent({} as Route.ComponentProps);
19-
} catch (e) {
20-
// Error is captured by Sentry, rethrow for error boundary
21-
throw e;
22-
}
23-
return {};
24-
}
25-
26-
export default ServerComponent;
Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
import type { Route } from './+types/server-component-not-found';
1+
import { wrapServerComponent } from '@sentry/react-router';
22

3-
// This route demonstrates that 404 responses are NOT captured as errors
4-
export async function loader() {
5-
// Throw a 404 response
3+
async function NotFoundServerComponent() {
64
throw new Response('Not Found', { status: 404 });
75
}
86

9-
export default function NotFoundServerComponentPage() {
10-
return (
11-
<main>
12-
<h1>Not Found Server Component</h1>
13-
<p>This triggers a 404 response.</p>
14-
</main>
15-
);
16-
}
7+
export default wrapServerComponent(NotFoundServerComponent, {
8+
componentRoute: '/rsc/server-component-not-found',
9+
componentType: 'Page',
10+
});

dev-packages/e2e-tests/test-applications/react-router-7-rsc/app/routes/rsc/server-component-param.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { wrapServerComponent } from '@sentry/react-router';
12
import type { Route } from './+types/server-component-param';
23

3-
export default async function ParamServerComponent({ params }: Route.ComponentProps) {
4+
async function ParamServerComponent({ params }: Route.ComponentProps) {
45
await new Promise(resolve => setTimeout(resolve, 10));
56

67
return (
@@ -10,3 +11,8 @@ export default async function ParamServerComponent({ params }: Route.ComponentPr
1011
</main>
1112
);
1213
}
14+
15+
export default wrapServerComponent(ParamServerComponent, {
16+
componentRoute: '/rsc/server-component/:param',
17+
componentType: 'Page',
18+
});
Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
import { redirect } from 'react-router';
2-
import type { Route } from './+types/server-component-redirect';
2+
import { wrapServerComponent } from '@sentry/react-router';
33

4-
// This route demonstrates that redirects are NOT captured as errors
5-
export async function loader() {
6-
// Redirect to home page
4+
async function RedirectServerComponent() {
75
throw redirect('/');
86
}
97

10-
export default function RedirectServerComponentPage() {
11-
return (
12-
<main>
13-
<h1>Redirect Server Component</h1>
14-
<p>You should be redirected and not see this.</p>
15-
</main>
16-
);
17-
}
8+
export default wrapServerComponent(RedirectServerComponent, {
9+
componentRoute: '/rsc/server-component-redirect',
10+
componentType: 'Page',
11+
});
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1+
import { wrapServerComponent } from '@sentry/react-router';
12
import type { Route } from './+types/server-component';
23

3-
export default async function ServerComponent({ loaderData }: Route.ComponentProps) {
4+
async function ServerComponent({ loaderData }: Route.ComponentProps) {
45
await new Promise(resolve => setTimeout(resolve, 10));
56

67
return (
78
<main>
89
<h1>Server Component</h1>
9-
<p>This demonstrates an auto-wrapped server component.</p>
10+
<p>This demonstrates a manually wrapped server component.</p>
1011
<p data-testid="loader-message">Message: {loaderData?.message ?? 'No loader data'}</p>
1112
</main>
1213
);
1314
}
1415

16+
export default wrapServerComponent(ServerComponent, {
17+
componentRoute: '/rsc/server-component',
18+
componentType: 'Page',
19+
});
20+
1521
export async function loader() {
1622
return { message: 'Hello from server loader!' };
1723
}

0 commit comments

Comments
 (0)