Search code examples
typescriptnestjssource-mapssentry

Sentry not getting TypeScript source maps when integrated with NestJS


I've created a small NestJS project recently which I attempting to integrate Sentry into. I have followed the instructions on the Nest-Raven package readme, along with the instructions provided by Sentry for TypeScript integration.

Unfortunately I cannot seem to get Sentry to display the TypeScript sourcemaps, only the regular JS ones, as you can see here:

Sentry Sourcemaps

I have Sentry initialised in main.ts as per the instructions

import { NestFactory } from '@nestjs/core';
import { RewriteFrames } from '@sentry/integrations';
import * as Sentry from '@sentry/node';
import { AppModule } from './app.module';

// This allows TypeScript to detect our global value
declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace NodeJS {
    interface Global {
      __rootdir__: string;
    }
  }
}

global.__rootdir__ = __dirname || process.cwd();

async function bootstrap() {
  Sentry.init({
    dsn: 'https://mySentryDSN.ingest.sentry.io/0',
    integrations: [
      new RewriteFrames({
        root: global.__rootdir__,
      }),
    ],
  });
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

I have also set up Nest-Raven to use a Global Interceptor

import { APP_INTERCEPTOR } from '@nestjs/core';
import { RavenInterceptor, RavenModule } from 'nest-raven';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    RavenModule,
    ...
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_INTERCEPTOR,
      useValue: new RavenInterceptor(),
    },
  ],
})
export class AppModule {}

Has anyone else encountered this issue? I am thinking that perhaps I need to upload the sourcemaps directly to Sentry as per these intstructions, however as far as I know NestJS does not make use of Webpack so I am unsure how to proceed.


Solution

  • So it turns out the issue was the directory I was providing to the RewriteFrames constructor. I had initially copied the global.__rootdir__ implementation from the Sentry Typescript documentation, but during debugging I found that __dirname and process.cwd() were returning different paths.

      dirname: '/Users/<name>/Documents/Projects/nest-test-project/dist',
      cwd: '/Users/<name>/Documents/Projects/nest-test-project'
    

    Since __dirname was returning a truthy value, the path being given to Sentry was the one that included the dist folder. Once I changed the code to give Sentry the actual root path for the project, all of the Typescript sourcemaps were uploaded to Sentry.

    EDIT: Some people were asking for an example of my tsconfig and the above code. I've since written my own SentryModule for bootstrapping Sentry, but the gist of the change is to find wherever you are calling new RewriteFrames({...}) and pass the correct root, which in my case was process.cwd().

    tsconfig.json

    {
      "compilerOptions": {
        "module": "commonjs",
        "declaration": true,
        "removeComments": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "allowSyntheticDefaultImports": true,
        "target": "ES2017",
        "lib": [ "ES2020.Promise" ],
        "outDir": "./dist",
        "baseUrl": "./",
        "incremental": true,
        "sourceMap": true,
        "inlineSources": true,
        "sourceRoot": "/"
      }
    }
    
    

    main.ts or wherever Sentry is initialised

    import { RewriteFrames } from "@sentry/integrations";
    
    Sentry.init({
      dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
      integrations: [
        new RewriteFrames({
          root: process.cwd(),
        }),
      ],
    });