Skip to content

fix(nextjs): Exclude build-time files from page dependency manifests - #6058

Merged
lobsterkatie merged 3 commits into
masterfrom
kmclb-nextjs-exclude-build-files-from-nft
Nov 22, 2022
Merged

fix(nextjs): Exclude build-time files from page dependency manifests#6058
lobsterkatie merged 3 commits into
masterfrom
kmclb-nextjs-exclude-build-files-from-nft

Conversation

@lobsterkatie

@lobsterkatielobsterkatie commented Oct 27, 2022

Copy link
Copy Markdown
Member

When nextjs 12+ builds a user's app, it creates a .nft.json file for each page, listing all of the files upon which the page depends. This is used, for example, by Vercel, when it's bundling each page into its own lambda function.

Under the hood, nextjs uses the @vercel/nft package to do the dependency tracing. Unfortunately, it seems to run before treeshaking, so any file imported into a given module will be included, even if the thing which is imported from that file gets treeshaken away. In our case, that means that even though withSentryConfig will never be called in anyone's app (and therefore none of its dependents - not only our loaders but also sucrase and rollup, among other things - should be included in any page's dependency list), the fact that Sentry.initis included in a user's app, and that withSentryConfig is exported from index.server.js right alongside init, means that in fact files fromsrc/configare included when they shouldn't be.

Fortunately, nextjs runs @vercel/nft through a webpack plugin, and that plugin takes an option to exclude files. We therefore can add src/config/withSentryConfig.ts to that option's array when we're modifying the app's webpack config and it will prevent that file (and any of its descendants) from being included.

Notes:

  • Files in src/config come in three flavors: files modifying the user's webpack config, templates read in by our loaders, and files referenced by the code we inject (the wrappers). For historical reasons, src/config/index.ts only contains the first kind of file. Since it's not actually indexing all three kinds of files, I instead renamed it withSentryConfig.ts, after the only thing it exports. This not only makes it clearer what it's about, it also doesn't give the false impression that it's the single export point for everything in src/config.

  • To test this, I took a first stab at an integration test system focused on testing the code we use to modify the user's build. It's not especially fancy, and I'm very open to opinions on how it could be better, but it seems for the moment to at least do the trick we currently need.

  • One issue this PR doesn't address is the fact that we still have files from the browser SDK included in server-side page dependency manifests, because index.server.ts exports our react error boundary, and @sentry/react imports from @sentry/browser. It would take some work to make @sentry/react depend a little less on @sentry/browser and a little more on @sentry/utils and @sentry/core, such that we'd be able to exclude all files from @sentry/browser, so that will have to happen in a separate PR.

@lobsterkatielobsterkatie self-assigned this Nov 17, 2022
@lobsterkatie
lobsterkatieforce-pushed the kmclb-nextjs-exclude-build-files-from-nft branch from a85519a to e932b14CompareNovember 21, 2022 08:36
@github-actions

github-actionsBot commented Nov 21, 2022

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize
@sentry/browser - ES5 CDN Bundle (gzipped + minified)19.52 KB (+0.02% 🔺)
@sentry/browser - ES5 CDN Bundle (minified)60.39 KB (+0.03% 🔺)
@sentry/browser - ES6 CDN Bundle (gzipped + minified)18.18 KB (+0.04% 🔺)
@sentry/browser - ES6 CDN Bundle (minified)53.74 KB (+0.04% 🔺)
@sentry/browser - Webpack (gzipped + minified)19.91 KB (+0.02% 🔺)
@sentry/browser - Webpack (minified)65.2 KB (+0.03% 🔺)
@sentry/react - Webpack (gzipped + minified)19.94 KB (+0.01% 🔺)
@sentry/nextjs Client - Webpack (gzipped + minified)45.93 KB (+0.01% 🔺)
@sentry/browser + @sentry/tracing - ES5 CDN Bundle (gzipped + minified)26.36 KB (+0.02% 🔺)
@sentry/browser + @sentry/tracing - ES6 CDN Bundle (gzipped + minified)24.77 KB (+0.03% 🔺)

@lobsterkatie
lobsterkatieforce-pushed the kmclb-nextjs-exclude-build-files-from-nft branch 4 times, most recently from a1cc068 to 1c9d654CompareNovember 21, 2022 09:59
@@ -0,0 +1,34 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Should we delete this file?

import * as chalk from 'chalk';
import * as fs from 'fs';
import * as path from 'path';
import { WebpackPluginInstance } from 'webpack';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Since we're only using it as a type, would it make sense to do import type here?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it turns out I had to run it through types.ts because of pahen/madge#306. (See the comment I left in the file.) But in any case, I changed the import from types.ts to be a type import.

return proto.constructor.name === 'TraceEntryPointsPlugin';
}) as WebpackPluginInstance & { excludeFiles: string[] };
if (nftPlugin) {
nftPlugin.excludeFiles.push(path.join(__dirname, 'withSentryConfig.js'));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Should we be a bit more defensive here in case excludeFiles is undefined or whatever, or when Next.js changes stuff in future updates? Maybe we wrap this in a try-catch?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. Done.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it pushed?

@lobsterkatielobsterkatieNov 22, 2022

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Line 115.

nftPlugin.excludeFiles=nftPlugin.excludeFiles||[];

I suppose I could also make sure it's an array. One sec.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so I went with only using it if it's an array. If it's undefined, I could set it to be an array, but if it's undefined, it also means they've changed something and we should take a look. So I threw that possibility in with the branch where they've changed the data structure.

@lobsterkatie
lobsterkatieforce-pushed the kmclb-nextjs-exclude-build-files-from-nft branch from 1c9d654 to c674039CompareNovember 21, 2022 21:48
Comment threadpackages/nextjs/test/buildProcess/runTest.ts
@lobsterkatie
lobsterkatieforce-pushed the kmclb-nextjs-exclude-build-files-from-nft branch 3 times, most recently from 6919d55 to aebfe0eCompareNovember 22, 2022 01:58
@lobsterkatie
lobsterkatieforce-pushed the kmclb-nextjs-exclude-build-files-from-nft branch from aebfe0e to 280aee2CompareNovember 22, 2022 16:22
@lobsterkatie
lobsterkatie merged commit 3d9f0fd into masterNov 22, 2022
@lobsterkatie
lobsterkatie deleted the kmclb-nextjs-exclude-build-files-from-nft branch November 22, 2022 17:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@lobsterkatie@lforst@github-advanced-security