diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index dfb144b5946d..180cc1476325 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -144,7 +144,7 @@ async function addSentryToEntryProperty( // inject into all entry points which might contain user's code for (const entryPointName in newEntryProperty) { - if (shouldAddSentryToEntryPoint(entryPointName)) { + if (shouldAddSentryToEntryPoint(entryPointName, isServer)) { addFilesToExistingEntryPoint(newEntryProperty, entryPointName, filesToInject); } } @@ -251,10 +251,15 @@ function checkWebpackPluginOverrides( * Determine if this is an entry point into which both `Sentry.init()` code and the release value should be injected * * @param entryPointName The name of the entry point in question + * @param isServer Whether or not this function is being called in the context of a server build * @returns `true` if sentry code should be injected, and `false` otherwise */ -function shouldAddSentryToEntryPoint(entryPointName: string): boolean { - return entryPointName === 'pages/_app' || entryPointName.includes('pages/api'); +function shouldAddSentryToEntryPoint(entryPointName: string, isServer: boolean): boolean { + return ( + entryPointName === 'pages/_app' || + entryPointName.includes('pages/api') || + (isServer && entryPointName === 'pages/_error') + ); } /** @@ -295,7 +300,7 @@ export function getWebpackPluginOptions( configFile: hasSentryProperties ? 'sentry.properties' : undefined, stripPrefix: ['webpack://_N_E/'], urlPrefix, - entries: shouldAddSentryToEntryPoint, + entries: (entryPointName: string) => shouldAddSentryToEntryPoint(entryPointName, isServer), release: getSentryRelease(buildId), dryRun: isDev, }); diff --git a/packages/nextjs/test/config.test.ts b/packages/nextjs/test/config.test.ts index f9aa4018bdd9..c53143c59a0e 100644 --- a/packages/nextjs/test/config.test.ts +++ b/packages/nextjs/test/config.test.ts @@ -90,7 +90,7 @@ const defaultsObject = { defaultConfig: {} as NextConfigObject }; const serverWebpackConfig = { entry: () => Promise.resolve({ - 'pages/api/dogs/[name]': 'private-next-pages/api/dogs/[name].js', + 'pages/_error': 'private-next-pages/_error.js', 'pages/_app': ['./node_modules/smellOVision/index.js', 'private-next-pages/_app.js'], 'pages/api/simulator/dogStats/[name]': { import: 'private-next-pages/api/simulator/dogStats/[name].js' }, 'pages/api/simulator/leaderboard': { @@ -111,6 +111,7 @@ const clientWebpackConfig = { Promise.resolve({ main: './src/index.ts', 'pages/_app': 'next-client-pages-loader?page=%2F_app', + 'pages/_error': 'next-client-pages-loader?page=%2F_error', }), output: { filename: 'static/chunks/[name].js', path: '/Users/Maisey/projects/squirrelChasingSimulator/.next' }, target: 'web', @@ -316,8 +317,8 @@ describe('webpack config', () => { expect(finalWebpackConfig.entry).toEqual( expect.objectContaining({ // original entrypoint value is a string - // (was 'private-next-pages/api/dogs/[name].js') - 'pages/api/dogs/[name]': [rewriteFramesHelper, serverConfigFilePath, 'private-next-pages/api/dogs/[name].js'], + // (was 'private-next-pages/_error.js') + 'pages/_error': [rewriteFramesHelper, serverConfigFilePath, 'private-next-pages/_error.js'], // original entrypoint value is a string array // (was ['./node_modules/smellOVision/index.js', 'private-next-pages/_app.js']) @@ -379,6 +380,30 @@ describe('webpack config', () => { ); }); + it('injects user config file into `_error` in server bundle but not client bundle', async () => { + const finalServerWebpackConfig = await materializeFinalWebpackConfig({ + userNextConfig, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: serverBuildContext, + }); + const finalClientWebpackConfig = await materializeFinalWebpackConfig({ + userNextConfig, + incomingWebpackConfig: clientWebpackConfig, + incomingWebpackBuildContext: clientBuildContext, + }); + + expect(finalServerWebpackConfig.entry).toEqual( + expect.objectContaining({ + 'pages/_error': expect.arrayContaining([serverConfigFilePath]), + }), + ); + expect(finalClientWebpackConfig.entry).toEqual( + expect.objectContaining({ + 'pages/_error': expect.not.arrayContaining([clientConfigFilePath]), + }), + ); + }); + it('injects user config file into API routes', async () => { const finalWebpackConfig = await materializeFinalWebpackConfig({ userNextConfig, @@ -403,7 +428,7 @@ describe('webpack config', () => { ); }); - it('does not inject anything into non-_app, non-API routes', async () => { + it('does not inject anything into non-_app, non-_error, non-API routes', async () => { const finalWebpackConfig = await materializeFinalWebpackConfig({ userNextConfig, incomingWebpackConfig: clientWebpackConfig,