From c8a941c590d08faad4f9ef37dbb3e750d53a3a83 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Tue, 14 Sep 2021 11:42:43 -0700 Subject: [PATCH] ref(nextjs): Exclude cross-platform tracing code from bundles (#3978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `@sentry/tracing` package contains shared code, code which only applies to browser, and code which only applies to node. At the moment, webpack is unable to treeshake the former out of the server build and the latter out of the client build. This PR does that treeshaking manually, taking advantage of webpack 5’s new ability[1] to replace a module with an empty object by setting `resolve.alias. = false` in the webpack config. Notes: - All node tracing integrations have been moved into a `node` folder, so we don't need to worry that at some point a non-node integration might get added to `integrations` and be accidentally excluded. - Normally we only care about bundle size on the browser side, but since Vercel turns server routes into serverless functions, bundle size matters on the backend, too, so the change was made in both directions. - As a point of reference, on my test app it took the sentry portion of the client `_app` bundle down from ~32.3 kb to ~30.6 kb, which is a little over a 5% savings. [1] https://webpack.js.org/configuration/resolve/#resolvealias --- packages/nextjs/src/config/types.ts | 3 +++ packages/nextjs/src/config/webpack.ts | 18 ++++++++++++++++++ packages/tracing/src/integrations/index.ts | 8 ++++---- .../src/integrations/{ => node}/express.ts | 0 .../src/integrations/{ => node}/mongo.ts | 0 .../src/integrations/{ => node}/mysql.ts | 0 .../src/integrations/{ => node}/postgres.ts | 0 .../test/integrations/{ => node}/mongo.test.ts | 4 ++-- .../integrations/{ => node}/postgres.test.ts | 4 ++-- 9 files changed, 29 insertions(+), 8 deletions(-) rename packages/tracing/src/integrations/{ => node}/express.ts (100%) rename packages/tracing/src/integrations/{ => node}/mongo.ts (100%) rename packages/tracing/src/integrations/{ => node}/mysql.ts (100%) rename packages/tracing/src/integrations/{ => node}/postgres.ts (100%) rename packages/tracing/test/integrations/{ => node}/mongo.test.ts (96%) rename packages/tracing/test/integrations/{ => node}/postgres.test.ts (96%) diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index b577268f41cb..89f2d3f57e33 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -42,6 +42,9 @@ export type WebpackConfigObject = { output: { filename: string; path: string }; target: string; context: string; + resolve?: { + alias?: { [key: string]: string | boolean }; + }; } & { // other webpack options [key: string]: unknown; diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index cc1ee7f2898e..76dd5a8382da 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -60,6 +60,24 @@ export function constructWebpackConfigFunction( const origEntryProperty = newConfig.entry; newConfig.entry = async () => addSentryToEntryProperty(origEntryProperty, buildContext); + // In webpack 5, you can get webpack to replace any module you'd like with an empty object, just by setting its + // `resolve.alias` value to `false`. Not much of our code is neatly separated into "things node needs" and "things + // the browser needs," but where it is, we can save ~1.6 kb in eventual bundle size by excluding code we know we + // don't need. (Normally this would only matter for the client side, but because vercel turns backend code into + // serverless functions, it's worthwhile to do it for both.) + if (buildContext.webpack.version.startsWith('5')) { + const excludedTracingDir = buildContext.isServer ? 'browser' : 'integrations/node'; + newConfig.resolve = { + ...newConfig.resolve, + alias: { + ...newConfig.resolve?.alias, + [path.resolve(buildContext.dir, `./node_modules/@sentry/tracing/esm/${excludedTracingDir}`)]: false, + // TODO It's not clear if it will ever pull from `dist` (in testing it never does), so we may not need this. + [path.resolve(buildContext.dir, `./node_modules/@sentry/tracing/dist/${excludedTracingDir}`)]: false, + }, + }; + } + // Enable the Sentry plugin (which uploads source maps to Sentry when not in dev) by default const enableWebpackPlugin = buildContext.isServer ? !userNextConfig.sentry?.disableServerWebpackPlugin diff --git a/packages/tracing/src/integrations/index.ts b/packages/tracing/src/integrations/index.ts index 5a9bd10b2d3c..4231abf350e6 100644 --- a/packages/tracing/src/integrations/index.ts +++ b/packages/tracing/src/integrations/index.ts @@ -1,4 +1,4 @@ -export { Express } from './express'; -export { Postgres } from './postgres'; -export { Mysql } from './mysql'; -export { Mongo } from './mongo'; +export { Express } from './node/express'; +export { Postgres } from './node/postgres'; +export { Mysql } from './node/mysql'; +export { Mongo } from './node/mongo'; diff --git a/packages/tracing/src/integrations/express.ts b/packages/tracing/src/integrations/node/express.ts similarity index 100% rename from packages/tracing/src/integrations/express.ts rename to packages/tracing/src/integrations/node/express.ts diff --git a/packages/tracing/src/integrations/mongo.ts b/packages/tracing/src/integrations/node/mongo.ts similarity index 100% rename from packages/tracing/src/integrations/mongo.ts rename to packages/tracing/src/integrations/node/mongo.ts diff --git a/packages/tracing/src/integrations/mysql.ts b/packages/tracing/src/integrations/node/mysql.ts similarity index 100% rename from packages/tracing/src/integrations/mysql.ts rename to packages/tracing/src/integrations/node/mysql.ts diff --git a/packages/tracing/src/integrations/postgres.ts b/packages/tracing/src/integrations/node/postgres.ts similarity index 100% rename from packages/tracing/src/integrations/postgres.ts rename to packages/tracing/src/integrations/node/postgres.ts diff --git a/packages/tracing/test/integrations/mongo.test.ts b/packages/tracing/test/integrations/node/mongo.test.ts similarity index 96% rename from packages/tracing/test/integrations/mongo.test.ts rename to packages/tracing/test/integrations/node/mongo.test.ts index fa7b91ee681f..521e922b4f89 100644 --- a/packages/tracing/test/integrations/mongo.test.ts +++ b/packages/tracing/test/integrations/node/mongo.test.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/unbound-method */ import { Hub, Scope } from '@sentry/hub'; -import { Mongo } from '../../src/integrations/mongo'; -import { Span } from '../../src/span'; +import { Mongo } from '../../../src/integrations/node/mongo'; +import { Span } from '../../../src/span'; class Collection { public collectionName: string = 'mockedCollectionName'; diff --git a/packages/tracing/test/integrations/postgres.test.ts b/packages/tracing/test/integrations/node/postgres.test.ts similarity index 96% rename from packages/tracing/test/integrations/postgres.test.ts rename to packages/tracing/test/integrations/node/postgres.test.ts index 98bb45357783..d8c335f54d88 100644 --- a/packages/tracing/test/integrations/postgres.test.ts +++ b/packages/tracing/test/integrations/node/postgres.test.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/unbound-method */ import { Hub, Scope } from '@sentry/hub'; -import { Postgres } from '../../src/integrations/postgres'; -import { Span } from '../../src/span'; +import { Postgres } from '../../../src/integrations/node/postgres'; +import { Span } from '../../../src/span'; class PgClient { // https://node-postgres.com/api/client#clientquery