@@ -26,36 +26,50 @@ type EntryProperty = (() => Promise<EntryPropertyObject>) | EntryPropertyObject;
2626type EntryPropertyObject = PlainObject < string | Array < string > | EntryPointObject > ;
2727type EntryPointObject = { import : string | Array < string > } ;
2828
29+ const sentryClientConfig = './sentry.client.config.js' ;
30+ const sentryServerConfig = './sentry.server.config.js' ;
31+
2932/** Add a file (`injectee`) to a given element (`injectionPoint`) of the `entry` property */
3033const _injectFile = ( entryProperty : EntryPropertyObject , injectionPoint : string , injectee : string ) : void => {
3134 // can be a string, array of strings, or object whose `import` property is one of those two
3235 let injectedInto = entryProperty [ injectionPoint ] ;
33- // whatever the format, add in the sentry file
34- injectedInto =
35- typeof injectedInto === 'string'
36- ? // string case
37- [ injectee , injectedInto ]
38- : // not a string, must be an array or object
39- Array . isArray ( injectedInto )
40- ? // array case
41- [ injectee , ...injectedInto ]
42- : // object case
43- {
44- ...injectedInto ,
45- import :
46- typeof injectedInto . import === 'string'
47- ? // string case for inner property
48- [ injectee , injectedInto . import ]
49- : // array case for inner property
50- [ injectee , ...injectedInto . import ] ,
51- } ;
36+
37+ // Sometimes especially for older next.js versions it happens we don't have an entry point
38+ if ( ! injectedInto ) {
39+ // eslint-disable-next-line no-console
40+ console . error ( `[Sentry] Can't inject ${ injectee } , no entrypoint is defined.` ) ;
41+ return ;
42+ }
43+
44+ // In case we inject our client config, we need to add it after the frontend code
45+ // otherwise the runtime config isn't loaded. See: https://github.com/getsentry/sentry-javascript/issues/3485
46+ const isClient = injectee === sentryClientConfig ;
47+
48+ if ( typeof injectedInto === 'string' ) {
49+ injectedInto = isClient ? [ injectedInto , injectee ] : [ injectee , injectedInto ] ;
50+ } else if ( Array . isArray ( injectedInto ) ) {
51+ injectedInto = isClient ? [ ...injectedInto , injectee ] : [ injectee , ...injectedInto ] ;
52+ } else {
53+ let importVal : string | string [ ] | EntryPointObject ;
54+ if ( typeof injectedInto . import === 'string' ) {
55+ importVal = isClient ? [ injectedInto . import , injectee ] : [ injectee , injectedInto . import ] ;
56+ } else {
57+ // If it's not a string, the inner value is an array
58+ importVal = isClient ? [ ...injectedInto . import , injectee ] : [ injectee , ...injectedInto . import ] ;
59+ }
60+
61+ injectedInto = {
62+ ...injectedInto ,
63+ import : importVal ,
64+ } ;
65+ }
66+
5267 entryProperty [ injectionPoint ] = injectedInto ;
5368} ;
5469
5570const injectSentry = async ( origEntryProperty : EntryProperty , isServer : boolean ) : Promise < EntryProperty > => {
5671 // Out of the box, nextjs uses the `() => Promise<EntryPropertyObject>)` flavor of EntryProperty, where the returned
57- // object has string arrays for values. But because we don't know whether someone else has come along before us and
58- // changed that, we need to check a few things along the way.
72+ // object has string arrays for values.
5973 // The `entry` entry in a webpack config can be a string, array of strings, object, or function. By default, nextjs
6074 // sets it to an async function which returns the promise of an object of string arrays. Because we don't know whether
6175 // someone else has come along before us and changed that, we need to check a few things along the way. The one thing
@@ -72,13 +86,13 @@ const injectSentry = async (origEntryProperty: EntryProperty, isServer: boolean)
7286 Object . keys ( newEntryProperty ) . forEach ( key => {
7387 if ( key === 'pages/_document' || key . includes ( 'pages/api' ) ) {
7488 // for some reason, because we're now in a function, we have to cast again
75- _injectFile ( newEntryProperty as EntryPropertyObject , key , './sentry.server.config.js' ) ;
89+ _injectFile ( newEntryProperty as EntryPropertyObject , key , sentryServerConfig ) ;
7690 }
7791 } ) ;
7892 }
7993 // On the client, it's sufficient to inject it into the `main` JS code, which is included in every browser page.
8094 else {
81- _injectFile ( newEntryProperty , 'main' , './sentry.client.config.js' ) ;
95+ _injectFile ( newEntryProperty , 'main' , sentryClientConfig ) ;
8296 }
8397 // TODO: hack made necessary because the async-ness of this function turns our object back into a promise, meaning the
8498 // internal `next` code which should do this doesn't
0 commit comments