@@ -15,8 +15,7 @@ type WebpackExport = (config: WebpackConfig, options: WebpackOptions) => Webpack
1515
1616// The two arguments passed to the exported `webpack` function, as well as the thing it returns
1717type WebpackConfig = { devtool : string ; plugins : PlainObject [ ] ; entry : EntryProperty } ;
18- // TODO use real webpack types
19- type WebpackOptions = { dev : boolean ; isServer : boolean } ;
18+ type WebpackOptions = { dev : boolean ; isServer : boolean ; buildId : string } ;
2019
2120// For our purposes, the value for `entry` is either an object, or a function which returns such an object
2221type EntryProperty = ( ( ) => Promise < EntryPropertyObject > ) | EntryPropertyObject ;
@@ -27,33 +26,10 @@ type EntryProperty = (() => Promise<EntryPropertyObject>) | EntryPropertyObject;
2726type EntryPropertyObject = PlainObject < string | Array < string > | EntryPointObject > ;
2827type EntryPointObject = { import : string | Array < string > } ;
2928
30- const injectSentry = async ( origEntryProperty : EntryProperty , isServer : boolean ) : Promise < EntryProperty > => {
31- // Out of the box, nextjs uses the `() => Promise<EntryPropertyObject>)` flavor of EntryProperty, where the returned
32- // object has string arrays for values. But because we don't know whether someone else has come along before us and
33- // changed that, we need to check a few things along the way.
34-
35- // The `entry` entry in a webpack config can be a string, array of strings, object, or function. By default, nextjs
36- // sets it to an async function which returns the promise of an object of string arrays. Because we don't know whether
37- // someone else has come along before us and changed that, we need to check a few things along the way. The one thing
38- // we know is that it won't have gotten *simpler* in form, so we only need to worry about the object and function
39- // options. See https://webpack.js.org/configuration/entry-context/#entry.
40-
41- let newEntryProperty = origEntryProperty ;
42-
43- if ( typeof origEntryProperty === 'function' ) {
44- newEntryProperty = await origEntryProperty ( ) ;
45- }
46-
47- newEntryProperty = newEntryProperty as EntryPropertyObject ;
48-
49- // according to vercel, we only need to inject Sentry in one spot for server and one spot for client, and because
50- // those are used as bases, it will apply everywhere
51- const injectionPoint = isServer ? 'pages/_document' : 'main' ;
52- const injectee = isServer ? './sentry.server.config.js' : './sentry.client.config.js' ;
53-
29+ /** Add a file (`injectee`) to a given element (`injectionPoint`) of the `entry` property */
30+ const _injectFile = ( entryProperty : EntryPropertyObject , injectionPoint : string , injectee : string ) : void => {
5431 // can be a string, array of strings, or object whose `import` property is one of those two
55- let injectedInto = newEntryProperty [ injectionPoint ] ;
56-
32+ let injectedInto = entryProperty [ injectionPoint ] ;
5733 // whatever the format, add in the sentry file
5834 injectedInto =
5935 typeof injectedInto === 'string'
@@ -73,15 +49,42 @@ const injectSentry = async (origEntryProperty: EntryProperty, isServer: boolean)
7349 : // array case for inner property
7450 [ injectee , ...injectedInto . import ] ,
7551 } ;
52+ entryProperty [ injectionPoint ] = injectedInto ;
53+ } ;
7654
77- newEntryProperty [ injectionPoint ] = injectedInto ;
78-
55+ const injectSentry = async ( origEntryProperty : EntryProperty , isServer : boolean ) : Promise < EntryProperty > => {
56+ // 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.
59+ // The `entry` entry in a webpack config can be a string, array of strings, object, or function. By default, nextjs
60+ // sets it to an async function which returns the promise of an object of string arrays. Because we don't know whether
61+ // someone else has come along before us and changed that, we need to check a few things along the way. The one thing
62+ // we know is that it won't have gotten *simpler* in form, so we only need to worry about the object and function
63+ // options. See https://webpack.js.org/configuration/entry-context/#entry.
64+ let newEntryProperty = origEntryProperty ;
65+ if ( typeof origEntryProperty === 'function' ) {
66+ newEntryProperty = await origEntryProperty ( ) ;
67+ }
68+ newEntryProperty = newEntryProperty as EntryPropertyObject ;
69+ // On the server, we need to inject the SDK into both into the base page (`_document`) and into individual API routes
70+ // (which have no common base).
71+ if ( isServer ) {
72+ Object . keys ( newEntryProperty ) . forEach ( key => {
73+ if ( key === 'pages/_document' || key . includes ( 'pages/api' ) ) {
74+ // 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' ) ;
76+ }
77+ } ) ;
78+ }
79+ // On the client, it's sufficient to inject it into the `main` JS code, which is included in every browser page.
80+ else {
81+ _injectFile ( newEntryProperty , 'main' , './sentry.client.config.js' ) ;
82+ }
7983 // TODO: hack made necessary because the async-ness of this function turns our object back into a promise, meaning the
8084 // internal `next` code which should do this doesn't
8185 if ( 'main.js' in newEntryProperty ) {
8286 delete newEntryProperty [ 'main.js' ] ;
8387 }
84-
8588 return newEntryProperty ;
8689} ;
8790
@@ -97,7 +100,6 @@ export function withSentryConfig(
97100 providedWebpackPluginOptions : Partial < SentryCliPluginOptions > = { } ,
98101) : NextConfigExports {
99102 const defaultWebpackPluginOptions = {
100- release : getSentryRelease ( ) ,
101103 url : process . env . SENTRY_URL ,
102104 org : process . env . SENTRY_ORG ,
103105 project : process . env . SENTRY_PROJECT ,
@@ -144,6 +146,7 @@ export function withSentryConfig(
144146 // TODO it's not clear how to do this better, but there *must* be a better way
145147 new ( ( SentryWebpackPlugin as unknown ) as typeof defaultWebpackPlugin ) ( {
146148 dryRun : options . dev ,
149+ release : getSentryRelease ( options . buildId ) ,
147150 ...defaultWebpackPluginOptions ,
148151 ...providedWebpackPluginOptions ,
149152 } ) ,
0 commit comments