@@ -77,7 +77,7 @@ const _injectFile = (entryProperty: EntryPropertyObject, injectionPoint: string,
7777 entryProperty [ injectionPoint ] = injectedInto ;
7878} ;
7979
80- const injectSentry = async ( origEntryProperty : EntryProperty , isServer : boolean ) : Promise < EntryProperty > => {
80+ const injectSentry = async ( origEntryProperty : EntryProperty , isServer : boolean ) : Promise < EntryPropertyObject > => {
8181 // The `entry` entry in a webpack config can be a string, array of strings, object, or function. By default, nextjs
8282 // sets it to an async function which returns the promise of an object of string arrays. Because we don't know whether
8383 // someone else has come along before us and changed that, we need to check a few things along the way. The one thing
@@ -106,11 +106,7 @@ const injectSentry = async (origEntryProperty: EntryProperty, isServer: boolean)
106106 else {
107107 _injectFile ( newEntryProperty , 'main' , SENTRY_CLIENT_CONFIG_FILE ) ;
108108 }
109- // TODO: hack made necessary because the async-ness of this function turns our object back into a promise, meaning the
110- // internal `next` code which should do this doesn't
111- if ( 'main.js' in newEntryProperty ) {
112- delete newEntryProperty [ 'main.js' ] ;
113- }
109+
114110 return newEntryProperty ;
115111} ;
116112
@@ -178,9 +174,15 @@ export function withSentryConfig(
178174 newConfig . devtool = 'source-map' ;
179175 }
180176
181- // Inject user config files (`sentry.client.confg.js` and `sentry.server.config.js`), which is where `Sentry.init()`
182- // is called. By adding them here, we ensure that they're bundled by webpack as part of both server code and client code.
183- newConfig . entry = ( injectSentry ( newConfig . entry , options . isServer ) as unknown ) as EntryProperty ;
177+ // Tell webpack to inject user config files (containing the two `Sentry.init()` calls) into the appropriate output
178+ // bundles. Store a separate reference to the original `entry` value to avoid an infinite loop. (In a synchronous
179+ // world, `x = () => f(x)` is fine, because the dereferencing is guaranteed to happen before the assignment, meaning
180+ // we know f will get the original value of x. But in an async world, if we do `x = async () => f(x)`, the
181+ // assignment happens *before* the dereferencing, meaning f is passed the new value. In other words, in that
182+ // scenario, the new value is defined in terms of itself, with predictably bad consequences. Theoretically this
183+ // could also be fixed by using `bind`, but this is way simpler.)
184+ const origEntryProperty = newConfig . entry ;
185+ newConfig . entry = ( ) => injectSentry ( origEntryProperty , options . isServer ) ;
184186
185187 // Add the Sentry plugin, which uploads source maps to Sentry when not in dev
186188 newConfig . plugins . push (
0 commit comments