diff --git a/.size-limit.js b/.size-limit.js index 20cc71fb75f0..aee03e5a242c 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -46,7 +46,7 @@ module.exports = [ }, { name: '@sentry/nextjs Client - Webpack (gzipped + minified)', - path: 'packages/nextjs/build/esm/index.client.js', + path: 'packages/nextjs/build/esm/client/index.js', import: '{ init }', gzip: true, limit: '57 KB', diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index c7990d1fdb77..c1806fcf1ed0 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -9,10 +9,10 @@ "engines": { "node": ">=8" }, - "main": "build/cjs/index.server.js", - "module": "build/esm/index.server.js", - "browser": "build/esm/index.client.js", - "types": "build/types/index.server.d.ts", + "main": "build/cjs/index.js", + "module": "build/esm/index.js", + "browser": "build/esm/client/index.js", + "types": "build/types/index.types.d.ts", "publishConfig": { "access": "public" }, @@ -31,7 +31,6 @@ "tslib": "^1.9.3" }, "devDependencies": { - "@sentry/nextjs": "7.30.0", "@types/webpack": "^4.41.31", "eslint-plugin-react": "^7.31.11", "next": "10.1.3" @@ -56,7 +55,7 @@ "build:rollup:watch": "nodemon --ext ts --watch src scripts/buildRollup.ts", "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:npm": "ts-node ../../scripts/prepack.ts && npm pack ./build", - "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", + "circularDepCheck": "madge --circular src/index.ts && madge --circular src/client/index.ts && madge --circular src/index.types.ts", "clean": "rimraf build coverage sentry-nextjs-*.tgz", "fix": "run-s fix:eslint fix:prettier", "fix:eslint": "eslint . --format stylish --fix", diff --git a/packages/nextjs/rollup.npm.config.js b/packages/nextjs/rollup.npm.config.js index d605dc65f3eb..2329f9eafed1 100644 --- a/packages/nextjs/rollup.npm.config.js +++ b/packages/nextjs/rollup.npm.config.js @@ -5,11 +5,11 @@ export default [ makeBaseNPMConfig({ // We need to include `instrumentServer.ts` separately because it's only conditionally required, and so rollup // doesn't automatically include it when calculating the module dependency tree. - entrypoints: ['src/index.server.ts', 'src/index.client.ts', 'src/config/webpack.ts'], + entrypoints: ['src/index.ts', 'src/client/index.ts', 'src/config/webpack.ts'], // prevent this internal nextjs code from ending up in our built package (this doesn't happen automatially because // the name doesn't match an SDK dependency) - packageSpecificConfig: { external: ['next/router'] }, + packageSpecificConfig: { external: ['next/router', 'next/constants'] }, }), ), ...makeNPMConfigVariants( diff --git a/packages/nextjs/src/index.client.ts b/packages/nextjs/src/client/index.ts similarity index 83% rename from packages/nextjs/src/index.client.ts rename to packages/nextjs/src/client/index.ts index 98ea9928b8ed..08f5b113ba74 100644 --- a/packages/nextjs/src/index.client.ts +++ b/packages/nextjs/src/client/index.ts @@ -1,17 +1,16 @@ import { RewriteFrames } from '@sentry/integrations'; -import { configureScope, init as reactInit, Integrations } from '@sentry/react'; +import { BrowserOptions, configureScope, init as reactInit, Integrations } from '@sentry/react'; import { BrowserTracing, defaultRequestInstrumentationOptions, hasTracingEnabled } from '@sentry/tracing'; import { EventProcessor } from '@sentry/types'; -import { nextRouterInstrumentation } from './performance/client'; -import { buildMetadata } from './utils/metadata'; -import { NextjsOptions } from './utils/nextjsOptions'; -import { applyTunnelRouteOption } from './utils/tunnelRoute'; -import { addOrUpdateIntegration } from './utils/userIntegrations'; +import { buildMetadata } from '../common/metadata'; +import { addOrUpdateIntegration } from '../common/userIntegrations'; +import { nextRouterInstrumentation } from './performance'; +import { applyTunnelRouteOption } from './tunnelRoute'; export * from '@sentry/react'; -export { nextRouterInstrumentation } from './performance/client'; -export { captureUnderscoreErrorException } from './utils/_error'; +export { nextRouterInstrumentation } from './performance'; +export { captureUnderscoreErrorException } from '../common/_error'; export { Integrations }; @@ -35,7 +34,7 @@ const globalWithInjectedValues = global as typeof global & { }; /** Inits the Sentry NextJS SDK on the browser with the React SDK. */ -export function init(options: NextjsOptions): void { +export function init(options: BrowserOptions): void { applyTunnelRouteOption(options); buildMetadata(options, ['nextjs', 'react']); options.environment = options.environment || process.env.NODE_ENV; @@ -52,7 +51,7 @@ export function init(options: NextjsOptions): void { }); } -function addClientIntegrations(options: NextjsOptions): void { +function addClientIntegrations(options: BrowserOptions): void { let integrations = options.integrations || []; // This value is injected at build time, based on the output directory specified in the build config. Though a default diff --git a/packages/nextjs/src/performance/client.ts b/packages/nextjs/src/client/performance.ts similarity index 100% rename from packages/nextjs/src/performance/client.ts rename to packages/nextjs/src/client/performance.ts diff --git a/packages/nextjs/src/utils/tunnelRoute.ts b/packages/nextjs/src/client/tunnelRoute.ts similarity index 88% rename from packages/nextjs/src/utils/tunnelRoute.ts rename to packages/nextjs/src/client/tunnelRoute.ts index 16d4ce9b71cc..29ad48325bb9 100644 --- a/packages/nextjs/src/utils/tunnelRoute.ts +++ b/packages/nextjs/src/client/tunnelRoute.ts @@ -1,7 +1,6 @@ +import { BrowserOptions } from '@sentry/react'; import { dsnFromString, logger } from '@sentry/utils'; -import { NextjsOptions } from './nextjsOptions'; - const globalWithInjectedValues = global as typeof global & { __sentryRewritesTunnelPath__?: string; }; @@ -9,7 +8,7 @@ const globalWithInjectedValues = global as typeof global & { /** * Applies the `tunnel` option to the Next.js SDK options based on `withSentryConfig`'s `tunnelRoute` option. */ -export function applyTunnelRouteOption(options: NextjsOptions): void { +export function applyTunnelRouteOption(options: BrowserOptions): void { const tunnelRouteOption = globalWithInjectedValues.__sentryRewritesTunnelPath__; if (tunnelRouteOption && options.dsn) { const dsnComponents = dsnFromString(options.dsn); diff --git a/packages/nextjs/src/utils/_error.ts b/packages/nextjs/src/common/_error.ts similarity index 100% rename from packages/nextjs/src/utils/_error.ts rename to packages/nextjs/src/common/_error.ts diff --git a/packages/nextjs/src/utils/metadata.ts b/packages/nextjs/src/common/metadata.ts similarity index 100% rename from packages/nextjs/src/utils/metadata.ts rename to packages/nextjs/src/common/metadata.ts diff --git a/packages/nextjs/src/utils/userIntegrations.ts b/packages/nextjs/src/common/userIntegrations.ts similarity index 100% rename from packages/nextjs/src/utils/userIntegrations.ts rename to packages/nextjs/src/common/userIntegrations.ts diff --git a/packages/nextjs/src/config/index.ts b/packages/nextjs/src/config/index.ts new file mode 100644 index 000000000000..f537125a75f3 --- /dev/null +++ b/packages/nextjs/src/config/index.ts @@ -0,0 +1,2 @@ +export type { SentryWebpackPluginOptions } from './types'; +export { withSentryConfig } from './withSentryConfig'; diff --git a/packages/nextjs/src/config/templates/apiWrapperTemplate.ts b/packages/nextjs/src/config/templates/apiWrapperTemplate.ts index a16c3a0c7666..2f8dd2184301 100644 --- a/packages/nextjs/src/config/templates/apiWrapperTemplate.ts +++ b/packages/nextjs/src/config/templates/apiWrapperTemplate.ts @@ -9,12 +9,13 @@ // @ts-ignore See above // eslint-disable-next-line import/no-unresolved import * as origModule from '__SENTRY_WRAPPING_TARGET__'; +// eslint-disable-next-line import/no-extraneous-dependencies import * as Sentry from '@sentry/nextjs'; import type { PageConfig } from 'next'; // We import this from `wrappers` rather than directly from `next` because our version can work simultaneously with // multiple versions of next. See note in `wrappers/types` for more. -import type { NextApiHandler } from '../wrappers'; +import type { NextApiHandler } from '../../server/types'; type NextApiModule = ( | { diff --git a/packages/nextjs/src/config/templates/pageWrapperTemplate.ts b/packages/nextjs/src/config/templates/pageWrapperTemplate.ts index 116c0503fbef..e3b6b4e7e296 100644 --- a/packages/nextjs/src/config/templates/pageWrapperTemplate.ts +++ b/packages/nextjs/src/config/templates/pageWrapperTemplate.ts @@ -9,6 +9,7 @@ // @ts-ignore See above // eslint-disable-next-line import/no-unresolved import * as wrapee from '__SENTRY_WRAPPING_TARGET__'; +// eslint-disable-next-line import/no-extraneous-dependencies import * as Sentry from '@sentry/nextjs'; import type { GetServerSideProps, GetStaticProps, NextPage as NextPageComponent } from 'next'; diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 2b8d12792470..5c16b82286c7 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -1,4 +1,5 @@ -import { NEXT_PHASE_DEVELOPMENT_SERVER, NEXT_PHASE_PRODUCTION_BUILD } from '../utils/phases'; +import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from 'next/constants'; + import type { ExportedNextConfig, NextConfigFunction, @@ -50,7 +51,7 @@ function getFinalConfigObject( // In order to prevent all of our build-time code from being bundled in people's route-handling serverless functions, // we exclude `webpack.ts` and all of its dependencies from nextjs's `@vercel/nft` filetracing. We therefore need to // make sure that we only require it at build time or in development mode. - if (phase === NEXT_PHASE_PRODUCTION_BUILD || phase === NEXT_PHASE_DEVELOPMENT_SERVER) { + if (phase === PHASE_PRODUCTION_BUILD || phase === PHASE_DEVELOPMENT_SERVER) { // eslint-disable-next-line @typescript-eslint/no-var-requires const { constructWebpackConfigFunction } = require('./webpack'); return { diff --git a/packages/nextjs/src/config/wrappers/index.ts b/packages/nextjs/src/config/wrappers/index.ts deleted file mode 100644 index aa406b970e77..000000000000 --- a/packages/nextjs/src/config/wrappers/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type { AugmentedNextApiResponse, NextApiHandler, WrappedNextApiHandler } from './types'; - -export { withSentryGetStaticProps } from './withSentryGetStaticProps'; -export { withSentryServerSideGetInitialProps } from './withSentryServerSideGetInitialProps'; -export { withSentryServerSideAppGetInitialProps } from './withSentryServerSideAppGetInitialProps'; -export { withSentryServerSideDocumentGetInitialProps } from './withSentryServerSideDocumentGetInitialProps'; -export { withSentryServerSideErrorGetInitialProps } from './withSentryServerSideErrorGetInitialProps'; -export { withSentryGetServerSideProps } from './withSentryGetServerSideProps'; -export { withSentry, withSentryAPI } from './withSentryAPI'; diff --git a/packages/nextjs/src/index.ts b/packages/nextjs/src/index.ts new file mode 100644 index 000000000000..133b6ecf1da0 --- /dev/null +++ b/packages/nextjs/src/index.ts @@ -0,0 +1,2 @@ +export * from './config'; +export * from './server'; diff --git a/packages/nextjs/src/index.types.ts b/packages/nextjs/src/index.types.ts new file mode 100644 index 000000000000..5df30dffd580 --- /dev/null +++ b/packages/nextjs/src/index.types.ts @@ -0,0 +1,32 @@ +/* eslint-disable import/export */ + +// We export everything from both the client part of the SDK and from the server part. Some of the exports collide, +// which is not allowed, unless we redifine the colliding exports in this file - which we do below. +export * from './config'; +export * from './client'; +export * from './server'; + +import type { Integration, Options, StackParser } from '@sentry/types'; + +import type { BrowserOptions } from './client'; +import * as clientSdk from './client'; +import type { NodeOptions } from './server'; +import * as serverSdk from './server'; + +/** Initializes Sentry Next.js SDK */ +export declare function init(options: Options | BrowserOptions | NodeOptions): void; + +// We export a merged Integrations object so that users can (at least typing-wise) use all integrations everywhere. +export const Integrations = { ...clientSdk.Integrations, ...serverSdk.Integrations }; + +export declare const defaultIntegrations: Integration[]; +export declare const defaultStackParser: StackParser; + +// This variable is not a runtime variable but just a type to tell typescript that the methods below can either come +// from the client SDK or from the server SDK. TypeScript is smart enough to understand that these resolve to the same +// methods from `@sentry/core`. +declare const runtime: 'client' | 'server'; + +export const close = runtime === 'client' ? clientSdk.close : serverSdk.close; +export const flush = runtime === 'client' ? clientSdk.flush : serverSdk.flush; +export const lastEventId = runtime === 'client' ? clientSdk.lastEventId : serverSdk.lastEventId; diff --git a/packages/nextjs/src/index.server.ts b/packages/nextjs/src/server/index.ts similarity index 84% rename from packages/nextjs/src/index.server.ts rename to packages/nextjs/src/server/index.ts index 0500bd802300..2374b33ea519 100644 --- a/packages/nextjs/src/index.server.ts +++ b/packages/nextjs/src/server/index.ts @@ -1,24 +1,18 @@ import { Carrier, getHubFromCarrier, getMainCarrier } from '@sentry/core'; import { RewriteFrames } from '@sentry/integrations'; -import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node'; +import { configureScope, getCurrentHub, init as nodeInit, Integrations, NodeOptions } from '@sentry/node'; import { hasTracingEnabled } from '@sentry/tracing'; import { EventProcessor } from '@sentry/types'; import { escapeStringForRegex, logger } from '@sentry/utils'; import * as domainModule from 'domain'; import * as path from 'path'; +import { buildMetadata } from '../common/metadata'; +import { addOrUpdateIntegration, IntegrationWithExclusionOption } from '../common/userIntegrations'; import { isBuild } from './utils/isBuild'; -import { buildMetadata } from './utils/metadata'; -import { NextjsOptions } from './utils/nextjsOptions'; -import { addOrUpdateIntegration, IntegrationWithExclusionOption } from './utils/userIntegrations'; export * from '@sentry/node'; -export { captureUnderscoreErrorException } from './utils/_error'; - -// Exporting the Replay integration also from index.server.ts because TS only recognizes types from index.server.ts -// If we didn't export this, TS would complain that it can't find `Sentry.Replay` in the package, -// causing a build failure, when users initialize Replay in their sentry.client.config.js/ts file. -export { Replay } from './index.client'; +export { captureUnderscoreErrorException } from '../common/_error'; // Here we want to make sure to only include what doesn't have browser specifics // because or SSR of next.js we can only use this. @@ -40,7 +34,7 @@ export const IS_BUILD = isBuild(); const IS_VERCEL = !!process.env.VERCEL; /** Inits the Sentry NextJS SDK on node. */ -export function init(options: NextjsOptions): void { +export function init(options: NodeOptions): void { if (__DEBUG_BUILD__ && options.debug) { logger.enable(); } @@ -107,7 +101,7 @@ function sdkAlreadyInitialized(): boolean { return !!hub.getClient(); } -function addServerIntegrations(options: NextjsOptions): void { +function addServerIntegrations(options: NodeOptions): void { let integrations = options.integrations || []; // 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(); // eslint-disable-next-line deprecation/deprecation export { deprecatedIsBuild as isBuild }; -export type { SentryWebpackPluginOptions } from './config/types'; -export { withSentryConfig } from './config/withSentryConfig'; -export { - withSentryGetServerSideProps, - withSentryGetStaticProps, - withSentryServerSideGetInitialProps, - withSentryServerSideAppGetInitialProps, - withSentryServerSideDocumentGetInitialProps, - withSentryServerSideErrorGetInitialProps, - withSentryAPI, - withSentry, -} from './config/wrappers'; +export { withSentryGetStaticProps } from './withSentryGetStaticProps'; +export { withSentryServerSideGetInitialProps } from './withSentryServerSideGetInitialProps'; +export { withSentryServerSideAppGetInitialProps } from './withSentryServerSideAppGetInitialProps'; +export { withSentryServerSideDocumentGetInitialProps } from './withSentryServerSideDocumentGetInitialProps'; +export { withSentryServerSideErrorGetInitialProps } from './withSentryServerSideErrorGetInitialProps'; +export { withSentryGetServerSideProps } from './withSentryGetServerSideProps'; +export { withSentry, withSentryAPI } from './withSentryAPI'; diff --git a/packages/nextjs/src/config/wrappers/types.ts b/packages/nextjs/src/server/types.ts similarity index 100% rename from packages/nextjs/src/config/wrappers/types.ts rename to packages/nextjs/src/server/types.ts diff --git a/packages/nextjs/src/utils/isBuild.ts b/packages/nextjs/src/server/utils/isBuild.ts similarity index 54% rename from packages/nextjs/src/utils/isBuild.ts rename to packages/nextjs/src/server/utils/isBuild.ts index 0e6f6691bf44..92b9808f75b9 100644 --- a/packages/nextjs/src/utils/isBuild.ts +++ b/packages/nextjs/src/server/utils/isBuild.ts @@ -1,8 +1,8 @@ -import { NEXT_PHASE_PRODUCTION_BUILD } from './phases'; +import { PHASE_PRODUCTION_BUILD } from 'next/constants'; /** * Decide if the currently running process is part of the build phase or happening at runtime. */ export function isBuild(): boolean { - return process.env.NEXT_PHASE === NEXT_PHASE_PRODUCTION_BUILD; + return process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD; } diff --git a/packages/nextjs/src/utils/nextLogger.ts b/packages/nextjs/src/server/utils/nextLogger.ts similarity index 100% rename from packages/nextjs/src/utils/nextLogger.ts rename to packages/nextjs/src/server/utils/nextLogger.ts diff --git a/packages/nextjs/src/utils/platformSupportsStreaming.ts b/packages/nextjs/src/server/utils/platformSupportsStreaming.ts similarity index 100% rename from packages/nextjs/src/utils/platformSupportsStreaming.ts rename to packages/nextjs/src/server/utils/platformSupportsStreaming.ts diff --git a/packages/nextjs/src/config/wrappers/utils/responseEnd.ts b/packages/nextjs/src/server/utils/responseEnd.ts similarity index 100% rename from packages/nextjs/src/config/wrappers/utils/responseEnd.ts rename to packages/nextjs/src/server/utils/responseEnd.ts diff --git a/packages/nextjs/src/config/wrappers/wrapperUtils.ts b/packages/nextjs/src/server/utils/wrapperUtils.ts similarity index 98% rename from packages/nextjs/src/config/wrappers/wrapperUtils.ts rename to packages/nextjs/src/server/utils/wrapperUtils.ts index 18665040d45d..8883f1163f57 100644 --- a/packages/nextjs/src/config/wrappers/wrapperUtils.ts +++ b/packages/nextjs/src/server/utils/wrapperUtils.ts @@ -5,8 +5,8 @@ import { baggageHeaderToDynamicSamplingContext, extractTraceparentData } from '@ import * as domain from 'domain'; import { IncomingMessage, ServerResponse } from 'http'; -import { platformSupportsStreaming } from '../../utils/platformSupportsStreaming'; -import { autoEndTransactionOnResponseEnd, flushQueue } from './utils/responseEnd'; +import { platformSupportsStreaming } from './platformSupportsStreaming'; +import { autoEndTransactionOnResponseEnd, flushQueue } from './responseEnd'; declare module 'http' { interface IncomingMessage { diff --git a/packages/nextjs/src/config/wrappers/withSentryAPI.ts b/packages/nextjs/src/server/withSentryAPI.ts similarity index 98% rename from packages/nextjs/src/config/wrappers/withSentryAPI.ts rename to packages/nextjs/src/server/withSentryAPI.ts index 561939685aa0..acb15a4c5514 100644 --- a/packages/nextjs/src/config/wrappers/withSentryAPI.ts +++ b/packages/nextjs/src/server/withSentryAPI.ts @@ -11,9 +11,9 @@ import { } from '@sentry/utils'; import * as domain from 'domain'; -import { formatAsCode, nextLogger } from '../../utils/nextLogger'; -import { platformSupportsStreaming } from '../../utils/platformSupportsStreaming'; import type { AugmentedNextApiRequest, AugmentedNextApiResponse, NextApiHandler, WrappedNextApiHandler } from './types'; +import { formatAsCode, nextLogger } from './utils/nextLogger'; +import { platformSupportsStreaming } from './utils/platformSupportsStreaming'; import { autoEndTransactionOnResponseEnd, finishTransaction, flushQueue } from './utils/responseEnd'; /** diff --git a/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts b/packages/nextjs/src/server/withSentryGetServerSideProps.ts similarity index 91% rename from packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts rename to packages/nextjs/src/server/withSentryGetServerSideProps.ts index 8aa2244ea90e..76c8b848712a 100644 --- a/packages/nextjs/src/config/wrappers/withSentryGetServerSideProps.ts +++ b/packages/nextjs/src/server/withSentryGetServerSideProps.ts @@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing'; import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils'; import { GetServerSideProps } from 'next'; -import { isBuild } from '../../utils/isBuild'; -import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { + getTransactionFromRequest, + withErrorInstrumentation, + withTracedServerSideDataFetcher, +} from './utils/wrapperUtils'; /** * Create a wrapped version of the user's exported `getServerSideProps` function diff --git a/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts b/packages/nextjs/src/server/withSentryGetStaticProps.ts similarity index 93% rename from packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts rename to packages/nextjs/src/server/withSentryGetStaticProps.ts index 396c57c0652c..7220480b4117 100644 --- a/packages/nextjs/src/config/wrappers/withSentryGetStaticProps.ts +++ b/packages/nextjs/src/server/withSentryGetStaticProps.ts @@ -1,7 +1,7 @@ import { GetStaticProps } from 'next'; -import { isBuild } from '../../utils/isBuild'; -import { callDataFetcherTraced, withErrorInstrumentation } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { callDataFetcherTraced, withErrorInstrumentation } from './utils/wrapperUtils'; type Props = { [key: string]: unknown }; diff --git a/packages/nextjs/src/config/wrappers/withSentryServerSideAppGetInitialProps.ts b/packages/nextjs/src/server/withSentryServerSideAppGetInitialProps.ts similarity index 94% rename from packages/nextjs/src/config/wrappers/withSentryServerSideAppGetInitialProps.ts rename to packages/nextjs/src/server/withSentryServerSideAppGetInitialProps.ts index a136bbcdc96a..89ed3af12dc7 100644 --- a/packages/nextjs/src/config/wrappers/withSentryServerSideAppGetInitialProps.ts +++ b/packages/nextjs/src/server/withSentryServerSideAppGetInitialProps.ts @@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing'; import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils'; import App from 'next/app'; -import { isBuild } from '../../utils/isBuild'; -import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { + getTransactionFromRequest, + withErrorInstrumentation, + withTracedServerSideDataFetcher, +} from './utils/wrapperUtils'; type AppGetInitialProps = typeof App['getInitialProps']; diff --git a/packages/nextjs/src/config/wrappers/withSentryServerSideDocumentGetInitialProps.ts b/packages/nextjs/src/server/withSentryServerSideDocumentGetInitialProps.ts similarity index 96% rename from packages/nextjs/src/config/wrappers/withSentryServerSideDocumentGetInitialProps.ts rename to packages/nextjs/src/server/withSentryServerSideDocumentGetInitialProps.ts index a04aa11a3398..d08222b6064c 100644 --- a/packages/nextjs/src/config/wrappers/withSentryServerSideDocumentGetInitialProps.ts +++ b/packages/nextjs/src/server/withSentryServerSideDocumentGetInitialProps.ts @@ -1,8 +1,8 @@ import { hasTracingEnabled } from '@sentry/tracing'; import Document from 'next/document'; -import { isBuild } from '../../utils/isBuild'; -import { withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { withErrorInstrumentation, withTracedServerSideDataFetcher } from './utils/wrapperUtils'; type DocumentGetInitialProps = typeof Document.getInitialProps; diff --git a/packages/nextjs/src/config/wrappers/withSentryServerSideErrorGetInitialProps.ts b/packages/nextjs/src/server/withSentryServerSideErrorGetInitialProps.ts similarity index 93% rename from packages/nextjs/src/config/wrappers/withSentryServerSideErrorGetInitialProps.ts rename to packages/nextjs/src/server/withSentryServerSideErrorGetInitialProps.ts index 8ceae817e1bc..a0cadad23fa3 100644 --- a/packages/nextjs/src/config/wrappers/withSentryServerSideErrorGetInitialProps.ts +++ b/packages/nextjs/src/server/withSentryServerSideErrorGetInitialProps.ts @@ -3,8 +3,12 @@ import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils'; import { NextPageContext } from 'next'; import { ErrorProps } from 'next/error'; -import { isBuild } from '../../utils/isBuild'; -import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { + getTransactionFromRequest, + withErrorInstrumentation, + withTracedServerSideDataFetcher, +} from './utils/wrapperUtils'; type ErrorGetInitialProps = (context: NextPageContext) => Promise; diff --git a/packages/nextjs/src/config/wrappers/withSentryServerSideGetInitialProps.ts b/packages/nextjs/src/server/withSentryServerSideGetInitialProps.ts similarity index 92% rename from packages/nextjs/src/config/wrappers/withSentryServerSideGetInitialProps.ts rename to packages/nextjs/src/server/withSentryServerSideGetInitialProps.ts index 06d0f7766fec..d3760d792b9d 100644 --- a/packages/nextjs/src/config/wrappers/withSentryServerSideGetInitialProps.ts +++ b/packages/nextjs/src/server/withSentryServerSideGetInitialProps.ts @@ -2,8 +2,12 @@ import { hasTracingEnabled } from '@sentry/tracing'; import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils'; import { NextPage } from 'next'; -import { isBuild } from '../../utils/isBuild'; -import { getTransactionFromRequest, withErrorInstrumentation, withTracedServerSideDataFetcher } from './wrapperUtils'; +import { isBuild } from './utils/isBuild'; +import { + getTransactionFromRequest, + withErrorInstrumentation, + withTracedServerSideDataFetcher, +} from './utils/wrapperUtils'; type GetInitialProps = Required['getInitialProps']; diff --git a/packages/nextjs/src/utils/isESM.ts b/packages/nextjs/src/utils/isESM.ts deleted file mode 100644 index 30ce7f4e87de..000000000000 --- a/packages/nextjs/src/utils/isESM.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Determine if the given source code represents a file written using ES6 modules. - * - * The regexes used are from https://github.com/component/is-module, which got them from - * https://github.com/formatjs/js-module-formats, which says it got them from - * https://github.com/ModuleLoader/es-module-loader, though the originals are now nowhere to be found. - * - * @param moduleSource The source code of the module - * @returns True if the module contains ESM-patterned code, false otherwise. - */ -export function isESM(moduleSource: string): boolean { - const importExportRegex = - /(?:^\s*|[}{();,\n]\s*)(import\s+['"]|(import|module)\s+[^"'()\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; - const exportStarRegex = /(?:^\s*|[}{();,\n]\s*)(export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)"))/; - - return importExportRegex.test(moduleSource) || exportStarRegex.test(moduleSource); -} diff --git a/packages/nextjs/src/utils/nextjsOptions.ts b/packages/nextjs/src/utils/nextjsOptions.ts deleted file mode 100644 index ded1fe3f1d23..000000000000 --- a/packages/nextjs/src/utils/nextjsOptions.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NodeOptions } from '@sentry/node'; -import { BrowserOptions } from '@sentry/react'; -import { Options } from '@sentry/types'; - -export type NextjsOptions = Options | BrowserOptions | NodeOptions; diff --git a/packages/nextjs/src/utils/phases.ts b/packages/nextjs/src/utils/phases.ts deleted file mode 100644 index 17e11d404be1..000000000000 --- a/packages/nextjs/src/utils/phases.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const NEXT_PHASE_PRODUCTION_BUILD = 'phase-production-build'; -export const NEXT_PHASE_PRODUCTION_SERVER = 'phase-production-server'; -export const NEXT_PHASE_DEVELOPMENT_SERVER = 'phase-development-server'; diff --git a/packages/nextjs/test/index.client.test.ts b/packages/nextjs/test/clientSdk.test.ts similarity index 98% rename from packages/nextjs/test/index.client.test.ts rename to packages/nextjs/test/clientSdk.test.ts index 9ed02519e722..4a7577c21a33 100644 --- a/packages/nextjs/test/index.client.test.ts +++ b/packages/nextjs/test/clientSdk.test.ts @@ -6,8 +6,8 @@ import { Integration } from '@sentry/types'; import { logger } from '@sentry/utils'; import { JSDOM } from 'jsdom'; -import { init, Integrations, nextRouterInstrumentation } from '../src/index.client'; -import { UserIntegrationsFunction } from '../src/utils/userIntegrations'; +import { init, Integrations, nextRouterInstrumentation } from '../src/client'; +import { UserIntegrationsFunction } from '../src/common/userIntegrations'; const { BrowserTracing } = TracingIntegrations; diff --git a/packages/nextjs/test/config/withSentry.test.ts b/packages/nextjs/test/config/withSentry.test.ts index fa468b32670b..0ff2dca6018f 100644 --- a/packages/nextjs/test/config/withSentry.test.ts +++ b/packages/nextjs/test/config/withSentry.test.ts @@ -3,7 +3,8 @@ import * as Sentry from '@sentry/node'; import { Client, ClientOptions } from '@sentry/types'; import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'; -import { AugmentedNextApiResponse, withSentry, WrappedNextApiHandler } from '../../src/config/wrappers'; +import { withSentry } from '../../src/server'; +import type { AugmentedNextApiResponse, WrappedNextApiHandler } from '../../src/server/types'; const FLUSH_DURATION = 200; diff --git a/packages/nextjs/test/config/wrappers.test.ts b/packages/nextjs/test/config/wrappers.test.ts index abbefd93c3e8..ba742869ac49 100644 --- a/packages/nextjs/test/config/wrappers.test.ts +++ b/packages/nextjs/test/config/wrappers.test.ts @@ -2,16 +2,7 @@ import * as SentryCore from '@sentry/core'; import * as SentryTracing from '@sentry/tracing'; import { IncomingMessage, ServerResponse } from 'http'; -import { - withSentryGetServerSideProps, - withSentryServerSideGetInitialProps, - // TODO: Leaving `withSentryGetStaticProps` out for now until we figure out what to do with it - // withSentryGetStaticProps, - // TODO: Leaving these out for now until we figure out pages with no data fetchers - // withSentryServerSideAppGetInitialProps, - // withSentryServerSideDocumentGetInitialProps, - // withSentryServerSideErrorGetInitialProps, -} from '../../src/config/wrappers'; +import { withSentryGetServerSideProps, withSentryServerSideGetInitialProps } from '../../src/server'; const startTransactionSpy = jest.spyOn(SentryCore, 'startTransaction'); diff --git a/packages/nextjs/test/performance/client.test.ts b/packages/nextjs/test/performance/client.test.ts index 590a8254e109..1cd7d0e787a7 100644 --- a/packages/nextjs/test/performance/client.test.ts +++ b/packages/nextjs/test/performance/client.test.ts @@ -4,7 +4,7 @@ import { JSDOM } from 'jsdom'; import { NEXT_DATA as NextData } from 'next/dist/next-server/lib/utils'; import { default as Router } from 'next/router'; -import { nextRouterInstrumentation } from '../../src/performance/client'; +import { nextRouterInstrumentation } from '../../src/client/performance'; const globalObject = WINDOW as typeof WINDOW & { __BUILD_MANIFEST?: { diff --git a/packages/nextjs/test/index.server.test.ts b/packages/nextjs/test/serverSdk.test.ts similarity index 99% rename from packages/nextjs/test/index.server.test.ts rename to packages/nextjs/test/serverSdk.test.ts index 232d3b746f1e..56ef03377df6 100644 --- a/packages/nextjs/test/index.server.test.ts +++ b/packages/nextjs/test/serverSdk.test.ts @@ -4,7 +4,7 @@ import { Integration } from '@sentry/types'; import { GLOBAL_OBJ, logger } from '@sentry/utils'; import * as domain from 'domain'; -import { init } from '../src/index.server'; +import { init } from '../src/index'; const { Integrations } = SentryNode; diff --git a/packages/nextjs/test/utils/isESM.test.ts b/packages/nextjs/test/utils/isESM.test.ts deleted file mode 100644 index 22169377e730..000000000000 --- a/packages/nextjs/test/utils/isESM.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { isESM } from '../../src/utils/isESM'; - -// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import -describe('import syntax', function () { - it('recognizes import syntax', function () { - expect(isESM("import dogs from 'dogs';")).toBe(true); - expect(isESM("import * as dogs from 'dogs';")).toBe(true); - expect(isESM("import { maisey } from 'dogs';")).toBe(true); - expect(isESM("import { charlie as goofball } from 'dogs';")).toBe(true); - expect(isESM("import { default as maisey } from 'dogs';")).toBe(true); - expect(isESM("import { charlie, masiey } from 'dogs';")).toBe(true); - expect(isESM("import { masiey, charlie as pickle } from 'dogs';")).toBe(true); - expect(isESM("import charlie, { maisey } from 'dogs';")).toBe(true); - expect(isESM("import maisey, * as dogs from 'dogs';")).toBe(true); - expect(isESM("import 'dogs';")).toBe(true); - }); -}); - -// Based on https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/export -describe('export syntax', function () { - it('recognizes exported declarations', () => { - expect(isESM('export var maisey, charlie;')).toBe(true); - expect(isESM('export let charlie, maisey;')).toBe(true); - expect(isESM("export var maisey = 'silly', charlie = 'goofy';")).toBe(true); - expect(isESM("export let charlie = 'goofy', maisey = 'silly';")).toBe(true); - expect(isESM("export const maisey = 'silly', charlie = 'goofy';")).toBe(true); - expect(isESM('export function doDogStuff() { /* ... */ }')).toBe(true); - expect(isESM('export class Dog { /* ... */ }')).toBe(true); - expect(isESM('export function* generateWayTooManyPhotosOnMyPhone() { /* ... */ }')).toBe(true); - expect(isESM('export const { maisey, charlie } = dogObject;')).toBe(true); - expect(isESM('export const { charlie, masiey: maiseyTheDog } = dogObject;')).toBe(true); - expect(isESM('export const [ maisey, charlie ] = dogArray;')).toBe(true); - }); - - it('recognizes lists of exports', () => { - expect(isESM('export { maisey, charlie };')).toBe(true); - expect(isESM('export { charlie as charlieMcCharlerson, masiey as theMaiseyMaiseyDog };')).toBe(true); - expect(isESM('export { charlie as default };')).toBe(true); - }); - - it('recognizes default exports', () => { - expect(isESM("export default 'dogs are great';")).toBe(true); - expect(isESM('export default function doDogStuff() { /* ... */ }')).toBe(true); - expect(isESM('export default class Dog { /* ... */ }')).toBe(true); - expect(isESM('export default function* generateWayTooManyPhotosOnMyPhone() { /* ... */ }')).toBe(true); - expect(isESM('export default function () { /* ... */ }')).toBe(true); - expect(isESM('export default class { /* ... */ }')).toBe(true); - expect(isESM('export default function* () { /* ... */ }')).toBe(true); - }); - - it('recognizes exports directly from another module', () => { - expect(isESM("export * from 'dogs';")).toBe(true); - expect(isESM("export * as dogs from 'dogs';")).toBe(true); - expect(isESM("export { maisey, charlie } from 'dogs';")).toBe(true); - expect( - isESM("export { maisey as goodGirl, charlie as omgWouldYouJustPeeAlreadyIWantToGoToBed } from 'dogs';"), - ).toBe(true); - expect(isESM("export { default } from 'dogs';")).toBe(true); - expect(isESM("export { default, maisey } from 'dogs';")).toBe(true); - }); -}); - -describe('potential false positives', () => { - it("doesn't get fooled by look-alikes", () => { - expect(isESM("'this is an import statement'")).toBe(false); - expect(isESM("'this is an export statement'")).toBe(false); - expect(isESM('import(dogs)')).toBe(false); - }); -}); diff --git a/packages/nextjs/test/utils/tunnelRoute.test.ts b/packages/nextjs/test/utils/tunnelRoute.test.ts index 8a46f8b174ea..ae9b085da7ca 100644 --- a/packages/nextjs/test/utils/tunnelRoute.test.ts +++ b/packages/nextjs/test/utils/tunnelRoute.test.ts @@ -1,5 +1,6 @@ -import { NextjsOptions } from '../../src/utils/nextjsOptions'; -import { applyTunnelRouteOption } from '../../src/utils/tunnelRoute'; +import { BrowserOptions } from '@sentry/react'; + +import { applyTunnelRouteOption } from '../../src/client/tunnelRoute'; const globalWithInjectedValues = global as typeof global & { __sentryRewritesTunnelPath__?: string; @@ -14,7 +15,7 @@ describe('applyTunnelRouteOption()', () => { globalWithInjectedValues.__sentryRewritesTunnelPath__ = '/my-error-monitoring-route'; const options: any = { dsn: 'https://11111111111111111111111111111111@o2222222.ingest.sentry.io/3333333', - } as NextjsOptions; + } as BrowserOptions; applyTunnelRouteOption(options); @@ -25,7 +26,7 @@ describe('applyTunnelRouteOption()', () => { globalWithInjectedValues.__sentryRewritesTunnelPath__ = '/my-error-monitoring-route'; const options: any = { // no dsn - } as NextjsOptions; + } as BrowserOptions; applyTunnelRouteOption(options); @@ -35,7 +36,7 @@ describe('applyTunnelRouteOption()', () => { it("should not apply `tunnelRoute` option when `tunnelRoute` option wasn't injected", () => { const options: any = { dsn: 'https://11111111111111111111111111111111@o2222222.ingest.sentry.io/3333333', - } as NextjsOptions; + } as BrowserOptions; applyTunnelRouteOption(options); @@ -46,7 +47,7 @@ describe('applyTunnelRouteOption()', () => { globalWithInjectedValues.__sentryRewritesTunnelPath__ = '/my-error-monitoring-route'; const options: any = { dsn: 'https://11111111111111111111111111111111@example.com/3333333', - } as NextjsOptions; + } as BrowserOptions; applyTunnelRouteOption(options); diff --git a/packages/nextjs/test/utils/userIntegrations.test.ts b/packages/nextjs/test/utils/userIntegrations.test.ts index 7a8693a8a524..7a5d8d879fa1 100644 --- a/packages/nextjs/test/utils/userIntegrations.test.ts +++ b/packages/nextjs/test/utils/userIntegrations.test.ts @@ -1,5 +1,5 @@ -import type { IntegrationWithExclusionOption as Integration } from '../../src/utils/userIntegrations'; -import { addOrUpdateIntegration, UserIntegrations } from '../../src/utils/userIntegrations'; +import type { IntegrationWithExclusionOption as Integration } from '../../src/common/userIntegrations'; +import { addOrUpdateIntegration, UserIntegrations } from '../../src/common/userIntegrations'; type MockIntegrationOptions = { name: string;