Skip to content

Commit 59b0bf6

Browse files
author
Luca Forstner
authored
fix(nextjs): Make Next.js types isomorphic (#6707)
1 parent e332ae1 commit 59b0bf6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+124
-193
lines changed

.size-limit.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports = [
4646
},
4747
{
4848
name: '@sentry/nextjs Client - Webpack (gzipped + minified)',
49-
path: 'packages/nextjs/build/esm/index.client.js',
49+
path: 'packages/nextjs/build/esm/client/index.js',
5050
import: '{ init }',
5151
gzip: true,
5252
limit: '57 KB',

packages/nextjs/package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
"engines": {
1010
"node": ">=8"
1111
},
12-
"main": "build/cjs/index.server.js",
13-
"module": "build/esm/index.server.js",
14-
"browser": "build/esm/index.client.js",
15-
"types": "build/types/index.server.d.ts",
12+
"main": "build/cjs/index.js",
13+
"module": "build/esm/index.js",
14+
"browser": "build/esm/client/index.js",
15+
"types": "build/types/index.types.d.ts",
1616
"publishConfig": {
1717
"access": "public"
1818
},
@@ -31,7 +31,6 @@
3131
"tslib": "^1.9.3"
3232
},
3333
"devDependencies": {
34-
"@sentry/nextjs": "7.30.0",
3534
"@types/webpack": "^4.41.31",
3635
"eslint-plugin-react": "^7.31.11",
3736
"next": "10.1.3"
@@ -56,7 +55,7 @@
5655
"build:rollup:watch": "nodemon --ext ts --watch src scripts/buildRollup.ts",
5756
"build:types:watch": "tsc -p tsconfig.types.json --watch",
5857
"build:npm": "ts-node ../../scripts/prepack.ts && npm pack ./build",
59-
"circularDepCheck": "madge --circular src/index.client.ts && madge --circular --exclude 'config/types\\.ts' src/index.server.ts # see https://github.com/pahen/madge/issues/306",
58+
"circularDepCheck": "madge --circular src/index.ts && madge --circular src/client/index.ts && madge --circular src/index.types.ts",
6059
"clean": "rimraf build coverage sentry-nextjs-*.tgz",
6160
"fix": "run-s fix:eslint fix:prettier",
6261
"fix:eslint": "eslint . --format stylish --fix",

packages/nextjs/rollup.npm.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export default [
55
makeBaseNPMConfig({
66
// We need to include `instrumentServer.ts` separately because it's only conditionally required, and so rollup
77
// doesn't automatically include it when calculating the module dependency tree.
8-
entrypoints: ['src/index.server.ts', 'src/index.client.ts', 'src/config/webpack.ts'],
8+
entrypoints: ['src/index.ts', 'src/client/index.ts', 'src/config/webpack.ts'],
99

1010
// prevent this internal nextjs code from ending up in our built package (this doesn't happen automatially because
1111
// the name doesn't match an SDK dependency)
12-
packageSpecificConfig: { external: ['next/router'] },
12+
packageSpecificConfig: { external: ['next/router', 'next/constants'] },
1313
}),
1414
),
1515
...makeNPMConfigVariants(

packages/nextjs/src/index.client.ts renamed to packages/nextjs/src/client/index.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { RewriteFrames } from '@sentry/integrations';
2-
import { configureScope, init as reactInit, Integrations } from '@sentry/react';
2+
import { BrowserOptions, configureScope, init as reactInit, Integrations } from '@sentry/react';
33
import { BrowserTracing, defaultRequestInstrumentationOptions, hasTracingEnabled } from '@sentry/tracing';
44
import { EventProcessor } from '@sentry/types';
55

6-
import { nextRouterInstrumentation } from './performance/client';
7-
import { buildMetadata } from './utils/metadata';
8-
import { NextjsOptions } from './utils/nextjsOptions';
9-
import { applyTunnelRouteOption } from './utils/tunnelRoute';
10-
import { addOrUpdateIntegration } from './utils/userIntegrations';
6+
import { buildMetadata } from '../common/metadata';
7+
import { addOrUpdateIntegration } from '../common/userIntegrations';
8+
import { nextRouterInstrumentation } from './performance';
9+
import { applyTunnelRouteOption } from './tunnelRoute';
1110

1211
export * from '@sentry/react';
13-
export { nextRouterInstrumentation } from './performance/client';
14-
export { captureUnderscoreErrorException } from './utils/_error';
12+
export { nextRouterInstrumentation } from './performance';
13+
export { captureUnderscoreErrorException } from '../common/_error';
1514

1615
export { Integrations };
1716

@@ -35,7 +34,7 @@ const globalWithInjectedValues = global as typeof global & {
3534
};
3635

3736
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
38-
export function init(options: NextjsOptions): void {
37+
export function init(options: BrowserOptions): void {
3938
applyTunnelRouteOption(options);
4039
buildMetadata(options, ['nextjs', 'react']);
4140
options.environment = options.environment || process.env.NODE_ENV;
@@ -52,7 +51,7 @@ export function init(options: NextjsOptions): void {
5251
});
5352
}
5453

55-
function addClientIntegrations(options: NextjsOptions): void {
54+
function addClientIntegrations(options: BrowserOptions): void {
5655
let integrations = options.integrations || [];
5756

5857
// This value is injected at build time, based on the output directory specified in the build config. Though a default

packages/nextjs/src/utils/tunnelRoute.ts renamed to packages/nextjs/src/client/tunnelRoute.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1+
import { BrowserOptions } from '@sentry/react';
12
import { dsnFromString, logger } from '@sentry/utils';
23

3-
import { NextjsOptions } from './nextjsOptions';
4-
54
const globalWithInjectedValues = global as typeof global & {
65
__sentryRewritesTunnelPath__?: string;
76
};
87

98
/**
109
* Applies the `tunnel` option to the Next.js SDK options based on `withSentryConfig`'s `tunnelRoute` option.
1110
*/
12-
export function applyTunnelRouteOption(options: NextjsOptions): void {
11+
export function applyTunnelRouteOption(options: BrowserOptions): void {
1312
const tunnelRouteOption = globalWithInjectedValues.__sentryRewritesTunnelPath__;
1413
if (tunnelRouteOption && options.dsn) {
1514
const dsnComponents = dsnFromString(options.dsn);

packages/nextjs/src/config/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export type { SentryWebpackPluginOptions } from './types';
2+
export { withSentryConfig } from './withSentryConfig';

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
// @ts-ignore See above
1010
// eslint-disable-next-line import/no-unresolved
1111
import * as origModule from '__SENTRY_WRAPPING_TARGET__';
12+
// eslint-disable-next-line import/no-extraneous-dependencies
1213
import * as Sentry from '@sentry/nextjs';
1314
import type { PageConfig } from 'next';
1415

1516
// We import this from `wrappers` rather than directly from `next` because our version can work simultaneously with
1617
// multiple versions of next. See note in `wrappers/types` for more.
17-
import type { NextApiHandler } from '../wrappers';
18+
import type { NextApiHandler } from '../../server/types';
1819

1920
type NextApiModule = (
2021
| {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// @ts-ignore See above
1010
// eslint-disable-next-line import/no-unresolved
1111
import * as wrapee from '__SENTRY_WRAPPING_TARGET__';
12+
// eslint-disable-next-line import/no-extraneous-dependencies
1213
import * as Sentry from '@sentry/nextjs';
1314
import type { GetServerSideProps, GetStaticProps, NextPage as NextPageComponent } from 'next';
1415

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { NEXT_PHASE_DEVELOPMENT_SERVER, NEXT_PHASE_PRODUCTION_BUILD } from '../utils/phases';
1+
import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from 'next/constants';
2+
23
import type {
34
ExportedNextConfig,
45
NextConfigFunction,
@@ -50,7 +51,7 @@ function getFinalConfigObject(
5051
// In order to prevent all of our build-time code from being bundled in people's route-handling serverless functions,
5152
// we exclude `webpack.ts` and all of its dependencies from nextjs's `@vercel/nft` filetracing. We therefore need to
5253
// make sure that we only require it at build time or in development mode.
53-
if (phase === NEXT_PHASE_PRODUCTION_BUILD || phase === NEXT_PHASE_DEVELOPMENT_SERVER) {
54+
if (phase === PHASE_PRODUCTION_BUILD || phase === PHASE_DEVELOPMENT_SERVER) {
5455
// eslint-disable-next-line @typescript-eslint/no-var-requires
5556
const { constructWebpackConfigFunction } = require('./webpack');
5657
return {

packages/nextjs/src/config/wrappers/index.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

packages/nextjs/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './config';
2+
export * from './server';

packages/nextjs/src/index.types.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* eslint-disable import/export */
2+
3+
// We export everything from both the client part of the SDK and from the server part. Some of the exports collide,
4+
// which is not allowed, unless we redifine the colliding exports in this file - which we do below.
5+
export * from './config';
6+
export * from './client';
7+
export * from './server';
8+
9+
import type { Integration, Options, StackParser } from '@sentry/types';
10+
11+
import type { BrowserOptions } from './client';
12+
import * as clientSdk from './client';
13+
import type { NodeOptions } from './server';
14+
import * as serverSdk from './server';
15+
16+
/** Initializes Sentry Next.js SDK */
17+
export declare function init(options: Options | BrowserOptions | NodeOptions): void;
18+
19+
// We export a merged Integrations object so that users can (at least typing-wise) use all integrations everywhere.
20+
export const Integrations = { ...clientSdk.Integrations, ...serverSdk.Integrations };
21+
22+
export declare const defaultIntegrations: Integration[];
23+
export declare const defaultStackParser: StackParser;
24+
25+
// This variable is not a runtime variable but just a type to tell typescript that the methods below can either come
26+
// from the client SDK or from the server SDK. TypeScript is smart enough to understand that these resolve to the same
27+
// methods from `@sentry/core`.
28+
declare const runtime: 'client' | 'server';
29+
30+
export const close = runtime === 'client' ? clientSdk.close : serverSdk.close;
31+
export const flush = runtime === 'client' ? clientSdk.flush : serverSdk.flush;
32+
export const lastEventId = runtime === 'client' ? clientSdk.lastEventId : serverSdk.lastEventId;

packages/nextjs/src/index.server.ts renamed to packages/nextjs/src/server/index.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
import { Carrier, getHubFromCarrier, getMainCarrier } from '@sentry/core';
22
import { RewriteFrames } from '@sentry/integrations';
3-
import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node';
3+
import { configureScope, getCurrentHub, init as nodeInit, Integrations, NodeOptions } from '@sentry/node';
44
import { hasTracingEnabled } from '@sentry/tracing';
55
import { EventProcessor } from '@sentry/types';
66
import { escapeStringForRegex, logger } from '@sentry/utils';
77
import * as domainModule from 'domain';
88
import * as path from 'path';
99

10+
import { buildMetadata } from '../common/metadata';
11+
import { addOrUpdateIntegration, IntegrationWithExclusionOption } from '../common/userIntegrations';
1012
import { isBuild } from './utils/isBuild';
11-
import { buildMetadata } from './utils/metadata';
12-
import { NextjsOptions } from './utils/nextjsOptions';
13-
import { addOrUpdateIntegration, IntegrationWithExclusionOption } from './utils/userIntegrations';
1413

1514
export * from '@sentry/node';
16-
export { captureUnderscoreErrorException } from './utils/_error';
17-
18-
// Exporting the Replay integration also from index.server.ts because TS only recognizes types from index.server.ts
19-
// If we didn't export this, TS would complain that it can't find `Sentry.Replay` in the package,
20-
// causing a build failure, when users initialize Replay in their sentry.client.config.js/ts file.
21-
export { Replay } from './index.client';
15+
export { captureUnderscoreErrorException } from '../common/_error';
2216

2317
// Here we want to make sure to only include what doesn't have browser specifics
2418
// because or SSR of next.js we can only use this.
@@ -40,7 +34,7 @@ export const IS_BUILD = isBuild();
4034
const IS_VERCEL = !!process.env.VERCEL;
4135

4236
/** Inits the Sentry NextJS SDK on node. */
43-
export function init(options: NextjsOptions): void {
37+
export function init(options: NodeOptions): void {
4438
if (__DEBUG_BUILD__ && options.debug) {
4539
logger.enable();
4640
}
@@ -107,7 +101,7 @@ function sdkAlreadyInitialized(): boolean {
107101
return !!hub.getClient();
108102
}
109103

110-
function addServerIntegrations(options: NextjsOptions): void {
104+
function addServerIntegrations(options: NodeOptions): void {
111105
let integrations = options.integrations || [];
112106

113107
// This value is injected at build time, based on the output directory specified in the build config. Though a default
@@ -152,15 +146,10 @@ const deprecatedIsBuild = (): boolean => isBuild();
152146
// eslint-disable-next-line deprecation/deprecation
153147
export { deprecatedIsBuild as isBuild };
154148

155-
export type { SentryWebpackPluginOptions } from './config/types';
156-
export { withSentryConfig } from './config/withSentryConfig';
157-
export {
158-
withSentryGetServerSideProps,
159-
withSentryGetStaticProps,
160-
withSentryServerSideGetInitialProps,
161-
withSentryServerSideAppGetInitialProps,
162-
withSentryServerSideDocumentGetInitialProps,
163-
withSentryServerSideErrorGetInitialProps,
164-
withSentryAPI,
165-
withSentry,
166-
} from './config/wrappers';
149+
export { withSentryGetStaticProps } from './withSentryGetStaticProps';
150+
export { withSentryServerSideGetInitialProps } from './withSentryServerSideGetInitialProps';
151+
export { withSentryServerSideAppGetInitialProps } from './withSentryServerSideAppGetInitialProps';
152+
export { withSentryServerSideDocumentGetInitialProps } from './withSentryServerSideDocumentGetInitialProps';
153+
export { withSentryServerSideErrorGetInitialProps } from './withSentryServerSideErrorGetInitialProps';
154+
export { withSentryGetServerSideProps } from './withSentryGetServerSideProps';
155+
export { withSentry, withSentryAPI } from './withSentryAPI';
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { NEXT_PHASE_PRODUCTION_BUILD } from './phases';
1+
import { PHASE_PRODUCTION_BUILD } from 'next/constants';
22

33
/**
44
* Decide if the currently running process is part of the build phase or happening at runtime.
55
*/
66
export function isBuild(): boolean {
7-
return process.env.NEXT_PHASE === NEXT_PHASE_PRODUCTION_BUILD;
7+
return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD;
88
}

packages/nextjs/src/config/wrappers/wrapperUtils.ts renamed to packages/nextjs/src/server/utils/wrapperUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { baggageHeaderToDynamicSamplingContext, extractTraceparentData } from '@
55
import * as domain from 'domain';
66
import { IncomingMessage, ServerResponse } from 'http';
77

8-
import { platformSupportsStreaming } from '../../utils/platformSupportsStreaming';
9-
import { autoEndTransactionOnResponseEnd, flushQueue } from './utils/responseEnd';
8+
import { platformSupportsStreaming } from './platformSupportsStreaming';
9+
import { autoEndTransactionOnResponseEnd, flushQueue } from './responseEnd';
1010

1111
declare module 'http' {
1212
interface IncomingMessage {

packages/nextjs/src/config/wrappers/withSentryAPI.ts renamed to packages/nextjs/src/server/withSentryAPI.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import {
1111
} from '@sentry/utils';
1212
import * as domain from 'domain';
1313

14-
import { formatAsCode, nextLogger } from '../../utils/nextLogger';
15-
import { platformSupportsStreaming } from '../../utils/platformSupportsStreaming';
1614
import type { AugmentedNextApiRequest, AugmentedNextApiResponse, NextApiHandler, WrappedNextApiHandler } from './types';
15+
import { formatAsCode, nextLogger } from './utils/nextLogger';
16+
import { platformSupportsStreaming } from './utils/platformSupportsStreaming';
1717
import { autoEndTransactionOnResponseEnd, finishTransaction, flushQueue } from './utils/responseEnd';
1818

1919
/**

packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts renamed to packages/nextjs/src/server/withSentryGetServerSideProps.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing';
22
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
33
import { GetServerSideProps } from 'next';
44

5-
import { isBuild } from '../../utils/isBuild';
6-
import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils';
5+
import { isBuild } from './utils/isBuild';
6+
import {
7+
getTransactionFromRequest,
8+
withErrorInstrumentation,
9+
withTracedServerSideDataFetcher,
10+
} from './utils/wrapperUtils';
711

812
/**
913
* Create a wrapped version of the user's exported `getServerSideProps` function

packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts renamed to packages/nextjs/src/server/withSentryGetStaticProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { GetStaticProps } from 'next';
22

3-
import { isBuild } from '../../utils/isBuild';
4-
import { callDataFetcherTraced, withErrorInstrumentation } from './wrapperUtils';
3+
import { isBuild } from './utils/isBuild';
4+
import { callDataFetcherTraced, withErrorInstrumentation } from './utils/wrapperUtils';
55

66
type Props = { [key: string]: unknown };
77

packages/nextjs/src/config/wrappers/withSentryServerSideAppGetInitialProps.ts renamed to packages/nextjs/src/server/withSentryServerSideAppGetInitialProps.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing';
22
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
33
import App from 'next/app';
44

5-
import { isBuild } from '../../utils/isBuild';
6-
import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils';
5+
import { isBuild } from './utils/isBuild';
6+
import {
7+
getTransactionFromRequest,
8+
withErrorInstrumentation,
9+
withTracedServerSideDataFetcher,
10+
} from './utils/wrapperUtils';
711

812
type AppGetInitialProps = typeof App['getInitialProps'];
913

packages/nextjs/src/config/wrappers/withSentryServerSideDocumentGetInitialProps.ts renamed to packages/nextjs/src/server/withSentryServerSideDocumentGetInitialProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { hasTracingEnabled } from '@sentry/tracing';
22
import Document from 'next/document';
33

4-
import { isBuild } from '../../utils/isBuild';
5-
import { withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils';
4+
import { isBuild } from './utils/isBuild';
5+
import { withErrorInstrumentation, withTracedServerSideDataFetcher } from './utils/wrapperUtils';
66

77
type DocumentGetInitialProps = typeof Document.getInitialProps;
88

packages/nextjs/src/config/wrappers/withSentryServerSideErrorGetInitialProps.ts renamed to packages/nextjs/src/server/withSentryServerSideErrorGetInitialProps.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
33
import { NextPageContext } from 'next';
44
import { ErrorProps } from 'next/error';
55

6-
import { isBuild } from '../../utils/isBuild';
7-
import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils';
6+
import { isBuild } from './utils/isBuild';
7+
import {
8+
getTransactionFromRequest,
9+
withErrorInstrumentation,
10+
withTracedServerSideDataFetcher,
11+
} from './utils/wrapperUtils';
812

913
type ErrorGetInitialProps = (context: NextPageContext) => Promise<ErrorProps>;
1014

packages/nextjs/src/config/wrappers/withSentryServerSideGetInitialProps.ts renamed to packages/nextjs/src/server/withSentryServerSideGetInitialProps.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing';
22
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
33
import { NextPage } from 'next';
44

5-
import { isBuild } from '../../utils/isBuild';
6-
import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils';
5+
import { isBuild } from './utils/isBuild';
6+
import {
7+
getTransactionFromRequest,
8+
withErrorInstrumentation,
9+
withTracedServerSideDataFetcher,
10+
} from './utils/wrapperUtils';
711

812
type GetInitialProps = Required<NextPage>['getInitialProps'];
913

0 commit comments

Comments
 (0)