Skip to content

Commit 2fbaf45

Browse files
author
Luca Forstner
authored
feat(nextjs): Don't init SDK on Vercel Edge Runtime (#6408)
This PR fixes a problem where we crash out of the box on Vercel and also in production builds when the `experimental-edge` runtime is used in API routes. We use the fact that Next.js string replaces the global `EdgeRuntime` when a server bundle is supposed to be run on the edge runtime. If this is the case we no-op `Sentry.init` and log a message. We also have to not wrap the API routes automatically in that case. Tried to add quick tests that test if the API routes still crash. But with our integration test setup it was a pita to get working because this is only really a thing for Next.js 12+.
1 parent ac3453d commit 2fbaf45

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

packages/nextjs/src/config/templates/apiProxyLoaderTemplate.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type NextApiModule = (
2323
}
2424
// CJS export
2525
| NextApiHandler
26-
) & { config?: PageConfig };
26+
) & { config?: PageConfig & { runtime?: string } };
2727

2828
const userApiModule = origModule as NextApiModule;
2929

@@ -53,7 +53,13 @@ export const config = {
5353
},
5454
};
5555

56-
export default userProvidedHandler ? Sentry.withSentryAPI(userProvidedHandler, '__ROUTE__') : undefined;
56+
const isEdgeRuntime = origConfig.runtime === 'experimental-edge';
57+
58+
export default userProvidedHandler
59+
? isEdgeRuntime
60+
? userProvidedHandler
61+
: Sentry.withSentryAPI(userProvidedHandler, '__ROUTE__')
62+
: undefined;
5763

5864
// Re-export anything exported by the page module we're wrapping. When processing this code, Rollup is smart enough to
5965
// not include anything whose name matchs something we've explicitly exported above.

packages/nextjs/src/index.client.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { RewriteFrames } from '@sentry/integrations';
22
import { configureScope, init as reactInit, Integrations } from '@sentry/react';
33
import { BrowserTracing, defaultRequestInstrumentationOptions, hasTracingEnabled } from '@sentry/tracing';
44
import { EventProcessor } from '@sentry/types';
5+
import { logger } from '@sentry/utils';
56

67
import { nextRouterInstrumentation } from './performance/client';
78
import { buildMetadata } from './utils/metadata';
@@ -29,10 +30,23 @@ export { BrowserTracing };
2930
// Treeshakable guard to remove all code related to tracing
3031
declare const __SENTRY_TRACING__: boolean;
3132

33+
// This is a variable that Next.js will string replace during build with a string if run in an edge runtime from Next.js
34+
// v12.2.1-canary.3 onwards:
35+
// https://github.com/vercel/next.js/blob/166e5fb9b92f64c4b5d1f6560a05e2b9778c16fb/packages/next/build/webpack-config.ts#L206
36+
declare const EdgeRuntime: string | undefined;
37+
3238
type GlobalWithAssetPrefixPath = typeof global & { __rewriteFramesAssetPrefixPath__: string };
3339

3440
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
3541
export function init(options: NextjsOptions): void {
42+
if (typeof EdgeRuntime === 'string') {
43+
// If the SDK is imported when using the Vercel Edge Runtime, it will import the browser SDK, even though it is
44+
// running the server part of a Next.js application. We can use the `EdgeRuntime` to check for that case and make
45+
// the init call a no-op. This will prevent the SDK from crashing on the Edge Runtime.
46+
__DEBUG_BUILD__ && logger.log('Vercel Edge Runtime detected. Will not initialize SDK.');
47+
return;
48+
}
49+
3650
buildMetadata(options, ['nextjs', 'react']);
3751
options.environment = options.environment || process.env.NODE_ENV;
3852
addClientIntegrations(options);

packages/nextjs/src/index.server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ export { ErrorBoundary, showReportDialog, withErrorBoundary } from '@sentry/reac
2222
type GlobalWithDistDir = typeof global & { __rewriteFramesDistDir__: string };
2323
const domain = domainModule as typeof domainModule & { active: (domainModule.Domain & Carrier) | null };
2424

25+
// This is a variable that Next.js will string replace during build with a string if run in an edge runtime from Next.js
26+
// v12.2.1-canary.3 onwards:
27+
// https://github.com/vercel/next.js/blob/166e5fb9b92f64c4b5d1f6560a05e2b9778c16fb/packages/next/build/webpack-config.ts#L206
28+
declare const EdgeRuntime: string | undefined;
29+
2530
// Exporting this constant means we can compute it without the linter complaining, even if we stop directly using it in
2631
// this file. It's important that it be computed as early as possible, because one of its indicators is seeing 'build'
2732
// (as in the CLI command `next build`) in `process.argv`. Later on in the build process, everything's been spun out
@@ -37,6 +42,11 @@ export function init(options: NextjsOptions): void {
3742
logger.enable();
3843
}
3944

45+
if (typeof EdgeRuntime === 'string') {
46+
__DEBUG_BUILD__ && logger.log('Vercel Edge Runtime detected. Will not initialize SDK.');
47+
return;
48+
}
49+
4050
__DEBUG_BUILD__ && logger.log('Initializing SDK...');
4151

4252
if (sdkAlreadyInitialized()) {

0 commit comments

Comments
 (0)