-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(nextjs): Support cacheComponents on turbopack
#18304
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
Changes from 1 commit
f7fb5c4
5cf5d09
aa4ef7a
4d0ff96
84eeeb3
0fe6aa3
7eca48e
40af06a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| import type { Span, StartSpanOptions } from '@sentry/core'; | ||
| import { | ||
| SentryNonRecordingSpan, | ||
| startInactiveSpan as coreStartInactiveSpan, | ||
| startSpan as coreStartSpan, | ||
| startSpanManual as coreStartSpanManual, | ||
| } from '@sentry/core'; | ||
|
|
||
| /** | ||
| * Check if we're currently in a Next.js Cache Components context. | ||
| * Cache Components are rendered during the production build phase. | ||
| * | ||
| * @returns true if we're in a Cache Components context, false otherwise | ||
| * // todo: This is a heuristic check, we should use a more reliable way to detect a Cache Components context once Vercel exposes it. | ||
| */ | ||
| function isCacheComponentContext(): boolean { | ||
| return process.env.NEXT_PHASE === 'phase-production-build'; | ||
| } | ||
|
|
||
| /** | ||
| * Next.js-specific implementation of `startSpan` that skips span creation | ||
| * in Cache Components contexts (which render at build time). | ||
| * | ||
| * When in a Cache Components context, we execute the callback with a non-recording span | ||
| * and return early without creating an actual span, since spans don't make sense at build time. | ||
| * | ||
| * @param options - Options for starting the span | ||
| * @param callback - Callback function that receives the span | ||
| * @returns The return value of the callback | ||
| */ | ||
| export function startSpan<T>(options: StartSpanOptions, callback: (span: Span) => T): T { | ||
| if (isCacheComponentContext()) { | ||
| // Cache Components render at build time, so spans don't make sense | ||
| // Execute callback with a non-recording span (no crypto calls) and return early | ||
| // Use placeholder IDs since this span won't be sent to Sentry anyway | ||
| const nonRecordingSpan = new SentryNonRecordingSpan({ | ||
| traceId: '00000000000000000000000000000000', | ||
| spanId: '0000000000000000', | ||
| }); | ||
| return callback(nonRecordingSpan); | ||
| } | ||
|
|
||
| return coreStartSpan(options, callback); | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * When in a Cache Components context, we execute the callback with a non-recording span | ||
| * and return early without creating an actual span, since spans don't make sense at build time. | ||
| * | ||
| * @param options - Options for starting the span | ||
| * @param callback - Callback function that receives the span and finish function | ||
| * @returns The return value of the callback | ||
| */ | ||
| export function startSpanManual<T>(options: StartSpanOptions, callback: (span: Span, finish: () => void) => T): T { | ||
| if (isCacheComponentContext()) { | ||
| // Cache Components render at build time, so spans don't make sense | ||
| // Execute callback with a non-recording span (no crypto calls) and return early | ||
| // Use placeholder IDs since this span won't be sent to Sentry anyway | ||
| const nonRecordingSpan = new SentryNonRecordingSpan({ | ||
| traceId: '00000000000000000000000000000000', | ||
| spanId: '0000000000000000', | ||
| }); | ||
| return callback(nonRecordingSpan, () => nonRecordingSpan.end()); | ||
| } | ||
|
|
||
| return coreStartSpanManual(options, callback); | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * When in a Cache Components context, we return a non-recording span and return early | ||
| * without creating an actual span, since spans don't make sense at build time. | ||
| * | ||
| * @param options - Options for starting the span | ||
| * @returns A non-recording span (in Cache Components context) or the created span | ||
| */ | ||
| export function startInactiveSpan(options: StartSpanOptions): Span { | ||
| if (isCacheComponentContext()) { | ||
| // Cache Components render at build time, so spans don't make sense | ||
| // Return a non-recording span (no crypto calls) and return early | ||
| // Use placeholder IDs since this span won't be sent to Sentry anyway | ||
| return new SentryNonRecordingSpan({ | ||
| traceId: '00000000000000000000000000000000', | ||
| spanId: '0000000000000000', | ||
| }); | ||
| } | ||
|
|
||
| return coreStartInactiveSpan(options); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,9 @@ import { distDirRewriteFramesIntegration } from './distDirRewriteFramesIntegrati | |
| export * from '@sentry/vercel-edge'; | ||
| export * from '../common'; | ||
| export { captureUnderscoreErrorException } from '../common/pages-router-instrumentation/_error'; | ||
|
|
||
| // Override core span methods with Next.js-specific implementations that support Cache Components | ||
| export { startSpan, startSpanManual, startInactiveSpan } from '../common/utils/nextSpan'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A more robust change here might be to set a different acs for nextjs when you initialize the sdk server-side. That means people can still use imports from
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But we would not call init in this case (of a build) |
||
| export { wrapApiHandlerWithSentry } from './wrapApiHandlerWithSentry'; | ||
|
|
||
| export type EdgeOptions = VercelEdgeOptions; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So right now now, all
startSpanoperations performed by users will be using the non-recording spans?I suppose that means they can't manually instrument anything until the heuristic gets changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be
phase-production-buildonly during the build. During runtime tracing works as usual. Our tracing did not have any effect during build-time anyway sinceinstrumentation.tsdoes not get registered – but we still ran into the uuid calls thenThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that makes a lot of sense 👍