getsentry/sentry-javascript

Sourcemap not working on pinia stores in nuxt

Opened this issue · 6 comments

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nuxt

SDK Version

10.11.0

Framework Version

3.17.6

Link to Sentry event

https://revolutionrace-ab.sentry.io/issues/64525602/?environment=production&project=4509626362429520&query=is%3Aunresolved&referrer=issue-stream

Reproduction Example/SDK Setup

sentry.client.config.ts

import * as Sentry from '@sentry/nuxt';
Sentry.init({
  environment: useRuntimeConfig().public.Environment,
  release: useRuntimeConfig().public.BuildId,
  dsn: useRuntimeConfig().public.SentryDsn,
  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
  // This sets the sample rate to be 10%. You may want this to be 100% while
  // in development and sample at a lower rate in production
  replaysSessionSampleRate: useRuntimeConfig().public.Environment === 'production' ? 0.1 : 1.0,
  // If the entire session is not sampled, use the below sample rate to sample
  // sessions when an error occurs.
  replaysOnErrorSampleRate: 1.0,
  // If you don't want to use Session Replay, just remove the line below:
  integrations: [Sentry.replayIntegration()],
  // Setting this option to true will print useful information to the console while you're setting up Sentry.
  debug: false,
});

sentry.server.config.ts

import * as Sentry from '@sentry/nuxt';
Sentry.init({
  environment: useRuntimeConfig().public.Environment,
  release: useRuntimeConfig().public.BuildId,
  dsn: useRuntimeConfig().public.SentryDsn,
  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
  // Setting this option to true will print useful information to the console while you're setting up Sentry.
  debug: false,
});

nuxt.config.ts

-- Truncated --
  sentry: {
    org: 'revolutionrace-ab',
    project: 'storefront-nuxt',
    authToken: process.env.SentryAuthToken,
    release: {
      name: buildId,
    },
  },
  sourcemap: { client: 'hidden' },
-- Truncated --

Steps to Reproduce

  1. Create a nuxt project.
  2. Add pinia according to the documentation.
  3. Add @sentry/nuxt
  4. Make sure sourcemaps are uploaded
  5. Trigger an error within the pini store code.
  6. Check it in the Sentry ui.
  7. Notice that the code is minified in the ui.

Expected Result

I expect all ts, js and vue code to be visible non minified within the Sentry UI.

Actual Result

Image Image

Additional Context

Maybe we are missunderstanding what parts work for sourcemap info.

Hey @SebbeJohansson thanks for reaching out! Your setup looks ok to me but the error is thrown in a bundled 3rd party code frame that is not source mapped.

Hy, I just reproduced this and threw an error in a pinia store. However, it was source-mapped correctly. Like Charly already suspected: Are you bundling anything at some point?

I can share the reproduction if needed, but I was basically adding an error into an action here.

@SebbeJohansson the frames you're seeing are marked as In App because they seem to be bundled into your code. When we reproduced this, this was not the case. Could you share your full nuxt config?

Hi! Thanks for your responses! Ill try to include as much as I can from the code.
I dont think we are doing anything special.
nuxt.config.ts

export default defineNuxtConfig({
  compatibilityDate: '2025-03-12',
  nitro: {
    compressPublicAssets: true,
  },
  devtools: {
    enabled: JSON.parse(process.env.NUXT_DEVTOOLS_ENABLED ?? 'false'),

    timeline: {
      enabled: JSON.parse(process.env.NUXT_DEVTOOLS_TIMELINE_ENABLED ?? 'true'),
    },
  },
  runtimeConfig: {
    /* REDACTED */
  },
  // These will only be present in built mode.
  routeRules: [
    '/.well-known/**',
    '/flags/**',
    '/icons/**',
    '/fonts/**',
    '/logos/**',
    '/sizeguide/**',
    '/android-chrome-36x36.png',
    '/android-chrome-48x48.png',
    '/android-chrome-72x72.png',
    '/android-chrome-96x96.png',
    '/android-chrome-144x144.png',
    '/android-chrome-192x192.png',
    '/apple-icon-57x57.png',
    '/apple-icon-60x60.png',
    '/apple-icon-72x72.png',
    '/apple-icon-76x76.png',
    '/apple-icon-114x114.png',
    '/apple-icon-120x120.png',
    '/apple-icon-144x144.png',
    '/apple-icon-152x152.png',
    '/apple-icon-180x180.png',
    '/apple-icon.png',
    '/favicon-16x16.png',
    '/favicon-32x32.png',
    '/favicon-96x96.png',
    '/favicon.ico',
    '/manifest.json',
  ].reduce((routeRules, path) => ({ ...routeRules, [path]: staticAssetHeaders }), {}),
  storyblok: {
    accessToken: process.env.StoryblokAccessToken,
    componentsDir: '~/components/storyblok',
    apiOptions: {
      cache: {
        type: 'none',
      },
    },
  },
  modules: ['@pinia/nuxt', '@storyblok/nuxt', '@nuxt/eslint', '@sentry/nuxt/module'],
  vue: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('klarna-'),
    },
  },
  vite: {
    plugins: [GraphQLPlugin()],
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "@/assets/style/_vars.scss" as *;',
        },
      },
    },
    server: {
      allowedHosts: [{{hosts array}}],
    },
  },
  components: [
    {
      path: '~/components/facets',
      global: true,
      prefix: 'Facets',
    },
    {
      path: '~/components/blocks',
      global: true,
      prefix: 'Blocks',
    },
    {
      path: '~/components',
      extensions: ['vue'],
    },
    {
      path: '~/components/storyblok',
      global: true,
    },
  ],
  app: {
    head: {
      title: '',
      meta: [
        { name: 'theme-color', content: '#181516' },
        { name: 'msapplication-navbutton-color', content: '#181516' },
        { name: 'apple-mobile-web-app-capable', content: 'yes' },
        { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
        { name: 'mobile-web-app-capable', content: 'yes' },
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
        { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' },
        {
          rel: 'icon',
          type: 'image/png',
          sizes: '96x96',
          href: '/favicon-96x96.png',
        },
        {
          rel: 'icon',
          type: 'image/png',
          sizes: '16x16',
          href: '/favicon-16x16.png',
        },
        { rel: 'apple-touch-icon', sizes: '57x57', href: '/apple-icon-57x57.png' },
        { rel: 'apple-touch-icon', sizes: '60x60', href: '/apple-icon-60x60.png' },
        { rel: 'apple-touch-icon', sizes: '72x72', href: '/apple-icon-72x72.png' },
        { rel: 'apple-touch-icon', sizes: '76x76', href: '/apple-icon-76x76.png' },
        { rel: 'apple-touch-icon', sizes: '114x114', href: '/apple-icon-114x114.png' },
        { rel: 'apple-touch-icon', sizes: '120x120', href: '/apple-icon-120x120.png' },
        { rel: 'apple-touch-icon', sizes: '144x144', href: '/apple-icon-144x144.png' },
        { rel: 'apple-touch-icon', sizes: '152x152', href: '/apple-icon-152x152.png' },
        { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-icon-180x180.png' },
        { rel: 'manifest', href: '/manifest.json' },
        {
          rel: 'preload',
          href: '/fonts/trim/Trim-Light.woff2',
          as: 'font',
          type: 'font/woff2',
          crossorigin: 'anonymous',
        },
        {
          rel: 'preload',
          href: '/fonts/trim/Trim-Regular.woff2',
          as: 'font',
          type: 'font/woff2',
          crossorigin: 'anonymous',
        },
        {
          rel: 'preload',
          href: '/fonts/trim/Trim-Medium.woff2',
          as: 'font',
          type: 'font/woff2',
          crossorigin: 'anonymous',
        },
        {
          rel: 'preload',
          href: '/fonts/trim/Trim-Bold.woff2',
          as: 'font',
          type: 'font/woff2',
          crossorigin: 'anonymous',
        },
        {
          rel: 'preload',
          href: '/fonts/trim/Trim-ExtraBold.woff2',
          as: 'font',
          type: 'font/woff2',
          crossorigin: 'anonymous',
        },
        { rel: 'preconnect', href: 'https://www.googletagmanager.com', crossorigin: 'anonymous' },
      ],
    },
  },
  css: ['~/assets/style/index.scss'],
  postcss: {
    plugins: {
      'postcss-custom-media': {
        importFrom: [
          {
            customMedia: {
              '--tiny': '(max-width: 320px), (max-width: 767px) and (orientation: landscape)',
              '--phone': '(max-width: 767px)',
              '--phoneAndTablet': '(max-width: 1025px)',
              '--tablet': '(min-width: 768px) and (max-width: 1025px)',
              '--tabletAndDesktop': '(min-width: 768px)',
              '--desktop': '(min-width: 1026px)',
            },
          },
        ],
      },
      'postcss-preset-env': {},
    },
  },
  imports: {
    dirs: ['utils/**', 'composables/**'],
  },
  hooks: {
    // @see https://github.com/nuxt/nuxt/issues/27558
    'vite:extendConfig': (config) => {
      if (typeof config.server?.hmr === 'object') {
        config.server.hmr.protocol = 'wss';
        config.server.hmr.clientPort = 443;
        config.server.hmr.path = 'hmr/';
      }
    },
  },
  sentry: {
    org: '{{org name}}',
    project: 'storefront-nuxt',
    authToken: process.env.SentryAuthToken,
    release: {
      name: buildId,
    },
  },
  sourcemap: { client: 'hidden' },
});

package.json

{
  "name": "/* REDACTED */",
  "private": true,
  "scripts": {
    /* REDACTED */
  },
  "devDependencies": {
    /* REDACTED */
    "nuxt": "3.17.6",
    /* REDACTED */
    "typescript": "5.8.3"
  },
  "dependencies": {
    "@adyen/adyen-web": "6.9.0",
    "@apptus/esales-api": "3.3.1",
    "@gtm-support/vue-gtm": "2.2.0",
    "@pinia/nuxt": "0.5.1",
    "@sentry/nuxt": "10.11.0",
    /* REDACTED */
    "pinia": "2.1.7",
    "uuid": "11.1.0"
  },
  "resolutions": {
    "vue": "3.5.13"
  },
  "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
}

Yeah nothing out of the ordinary to spot here.

We'll probably just need to figure out why the 4 top frames in your event were marked as in_app – otherwise these frames would be collapsed.

cc @loewenheim