@@ -54,16 +54,25 @@ export function constructWebpackConfigFunction(
5454 ) : WebpackConfigObject {
5555 const { isServer, dev : isDev , dir : projectDir } = buildContext ;
5656 const runtime = isServer ? ( buildContext . nextRuntime === 'edge' ? 'edge' : 'server' ) : 'client' ;
57+ // Default page extensions per https://github.com/vercel/next.js/blob/f1dbc9260d48c7995f6c52f8fbcc65f08e627992/packages/next/server/config-shared.ts#L161
58+ const pageExtensions = userNextConfig . pageExtensions || [ 'tsx' , 'ts' , 'jsx' , 'js' ] ;
59+ const dotPrefixedPageExtensions = pageExtensions . map ( ext => `.${ ext } ` ) ;
60+ const pageExtensionRegex = pageExtensions . map ( escapeStringForRegex ) . join ( '|' ) ;
61+
62+ // We add `.ts` and `.js` back in because `pageExtensions` might not be relevant to the instrumentation file
63+ // e.g. user's setting `.mdx`. In that case we still want to default look up
64+ // `instrumentation.ts` and `instrumentation.js`
65+ const instrumentationFile = getInstrumentationFile ( projectDir , dotPrefixedPageExtensions . concat ( [ '.ts' , '.js' ] ) ) ;
5766
5867 if ( runtime !== 'client' ) {
59- warnAboutDeprecatedConfigFiles ( projectDir , runtime ) ;
68+ warnAboutDeprecatedConfigFiles ( projectDir , instrumentationFile , runtime ) ;
6069 }
6170 if ( runtime === 'server' ) {
6271 const nextJsVersion = getNextjsVersion ( ) ;
6372 const { major } = parseSemver ( nextJsVersion || '' ) ;
6473 // was added in v15 (https://github.com/vercel/next.js/pull/67539)
6574 if ( major && major >= 15 ) {
66- warnAboutMissingOnRequestErrorHandler ( projectDir ) ;
75+ warnAboutMissingOnRequestErrorHandler ( instrumentationFile ) ;
6776 }
6877 }
6978
@@ -110,11 +119,6 @@ export function constructWebpackConfigFunction(
110119 ? path . join ( appDirPath , '..' )
111120 : projectDir ;
112121
113- // Default page extensions per https://github.com/vercel/next.js/blob/f1dbc9260d48c7995f6c52f8fbcc65f08e627992/packages/next/server/config-shared.ts#L161
114- const pageExtensions = userNextConfig . pageExtensions || [ 'tsx' , 'ts' , 'jsx' , 'js' ] ;
115- const dotPrefixedPageExtensions = pageExtensions . map ( ext => `.${ ext } ` ) ;
116- const pageExtensionRegex = pageExtensions . map ( escapeStringForRegex ) . join ( '|' ) ;
117-
118122 const staticWrappingLoaderOptions = {
119123 appDir : appDirPath ,
120124 pagesDir : pagesDirPath ,
@@ -445,37 +449,29 @@ async function addSentryToClientEntryProperty(
445449}
446450
447451/**
448- * Make sure the instrumentation file has a `onRequestError` Handler
449- *
450- * @param projectDir The root directory of the project, where config files would be located
452+ * Gets the content of the user's instrumentation file
451453 */
452- function warnAboutMissingOnRequestErrorHandler ( projectDir : string ) : void {
453- const instrumentationPaths = [
454- [ 'src' , 'instrumentation.ts' ] ,
455- [ 'src' , 'instrumentation.js' ] ,
456- [ 'instrumentation.ts' ] ,
457- [ 'instrumentation.js' ] ,
458- ] ;
459- const instrumentationFile = instrumentationPaths
460- . map ( pathSegments => path . resolve ( projectDir , ...pathSegments ) )
461- . find ( function exists ( filePath : string ) : string | null {
462- try {
463- fs . accessSync ( filePath , fs . constants . F_OK ) ;
464- return filePath ;
465- } catch ( error ) {
466- return null ;
467- }
468- } ) ;
454+ function getInstrumentationFile ( projectDir : string , dotPrefixedExtensions : string [ ] ) : string | null {
455+ const paths = dotPrefixedExtensions . flatMap ( extension => [
456+ [ 'src' , `instrumentation${ extension } ` ] ,
457+ [ `instrumentation${ extension } ` ] ,
458+ ] ) ;
469459
470- function hasOnRequestErrorHandler ( absolutePath : string ) : boolean {
460+ for ( const pathSegments of paths ) {
471461 try {
472- const content = fs . readFileSync ( absolutePath , 'utf8' ) ;
473- return content . includes ( 'onRequestError' ) ;
474- } catch ( error ) {
475- return false ;
462+ return fs . readFileSync ( path . resolve ( projectDir , ...pathSegments ) , { encoding : 'utf-8' } ) ;
463+ } catch ( e ) {
464+ // no-op
476465 }
477466 }
478467
468+ return null ;
469+ }
470+
471+ /**
472+ * Make sure the instrumentation file has a `onRequestError` Handler
473+ */
474+ function warnAboutMissingOnRequestErrorHandler ( instrumentationFile : string | null ) : void {
479475 if ( ! instrumentationFile ) {
480476 if ( ! process . env . SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING ) {
481477 // eslint-disable-next-line no-console
@@ -488,7 +484,7 @@ function warnAboutMissingOnRequestErrorHandler(projectDir: string): void {
488484 return ;
489485 }
490486
491- if ( ! hasOnRequestErrorHandler ( instrumentationFile ) ) {
487+ if ( ! instrumentationFile . includes ( 'onRequestError' ) ) {
492488 // eslint-disable-next-line no-console
493489 console . warn (
494490 chalk . yellow (
@@ -505,27 +501,15 @@ function warnAboutMissingOnRequestErrorHandler(projectDir: string): void {
505501 * @param projectDir The root directory of the project, where config files would be located
506502 * @param platform Either "server" or "edge", so that we know which file to look for
507503 */
508- function warnAboutDeprecatedConfigFiles ( projectDir : string , platform : 'server' | 'edge' ) : void {
509- const hasInstrumentationHookWithIndicationsOfSentry = [
510- [ 'src' , 'instrumentation.ts' ] ,
511- [ 'src' , 'instrumentation.js' ] ,
512- [ 'instrumentation.ts' ] ,
513- [ 'instrumentation.js' ] ,
514- ] . some ( potentialInstrumentationHookPathSegments => {
515- try {
516- const instrumentationHookContent = fs . readFileSync (
517- path . resolve ( projectDir , ...potentialInstrumentationHookPathSegments ) ,
518- { encoding : 'utf-8' } ,
519- ) ;
520-
521- return (
522- instrumentationHookContent . includes ( '@sentry/' ) ||
523- instrumentationHookContent . match ( / s e n t r y \. ( s e r v e r | e d g e ) \. c o n f i g ( \. ( t s | j s ) ) ? / )
524- ) ;
525- } catch ( e ) {
526- return false ;
527- }
528- } ) ;
504+ function warnAboutDeprecatedConfigFiles (
505+ projectDir : string ,
506+ instrumentationFile : string | null ,
507+ platform : 'server' | 'edge' ,
508+ ) : void {
509+ const hasInstrumentationHookWithIndicationsOfSentry =
510+ instrumentationFile &&
511+ ( instrumentationFile . includes ( '@sentry/' ) ||
512+ instrumentationFile . match ( / s e n t r y \. ( s e r v e r | e d g e ) \. c o n f i g ( \. ( t s | j s ) ) ? / ) ) ;
529513
530514 if ( hasInstrumentationHookWithIndicationsOfSentry ) {
531515 return ;
@@ -535,7 +519,7 @@ function warnAboutDeprecatedConfigFiles(projectDir: string, platform: 'server' |
535519 if ( fs . existsSync ( path . resolve ( projectDir , filename ) ) ) {
536520 // eslint-disable-next-line no-console
537521 console . warn (
538- `[@sentry/nextjs] It appears you've configured a \`${ filename } \` file. Please ensure to put this file's content into the \`register()\` function of a Next.js instrumentation hook instead. To ensure correct functionality of the SDK, \`Sentry.init\` must be called inside \` instrumentation.ts\`. Learn more about setting up an instrumentation hook in Next.js: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation. You can safely delete the \`${ filename } \` file afterward.` ,
522+ `[@sentry/nextjs] It appears you've configured a \`${ filename } \` file. Please ensure to put this file's content into the \`register()\` function of a Next.js instrumentation file instead. To ensure correct functionality of the SDK, \`Sentry.init\` must be called inside of an instrumentation file. Learn more about setting up an instrumentation file in Next.js: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation. You can safely delete the \`${ filename } \` file afterward.` ,
539523 ) ;
540524 }
541525 }
0 commit comments