Skip to content

Sveltekit: Auto-upload sourcemaps + VitePWA breaks build #13601

@selfagency

Description

@selfagency

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/sveltekit

SDK Version

8.28.0

Framework Version

Sveltekit 2.5.24

Link to Sentry event

N/A

Reproduction Example/SDK Setup

vite.config.ts

/* region imports */
// types
import type { SvelteKitPWAOptions } from '@vite-pwa/sveltekit';

// svelte
import { sveltekit } from '@sveltejs/kit/vite';

// node
import { exec, execSync } from 'node:child_process';

// vite
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import webfontDownload from 'vite-plugin-webfont-dl';
import { defineConfig } from 'vitest/config';

// third-party dependencies
import svg from '@poppanator/sveltekit-svg';
import { sentrySvelteKit } from '@sentry/sveltekit';
import chokidar from 'chokidar';
import { Logger } from 'tslog';
/* endregion imports */

/* region variables */
// constants
const version = execSync('git rev-parse HEAD').toString().trim();

const log = new Logger(
  {
    type: 'pretty',
    prettyLogTemplate: '{{yyyy}}/{{mm}}/{{dd}} {{hh}}:{{MM}}:{{ss}} [{{name}}] {{logLevelName}} {{filePathWithLine}} ',
  },
  { main: true, sub: false }
).getSubLogger({ name: 'vite' });
/* endregion variables */

/* region methods */
function watchAndRun(path: string, command: string) {
  return {
    name: 'watch-and-run',
    configureServer() {
      chokidar.watch(path).on('change', () => {
        // log.info(`File ${path} has been changed`);
        exec(command, (error, _, stderr) => {
          if (error) {
            log.error(error);
            return;
          }
          if (stderr) {
            log.error(stderr);
            return;
          }
          // log.info(`stdout: ${stdout}`);
        });
      });
    },
  };
}
/* endregion methods */

const pwaOptions = {
  devOptions: {
    enabled: false,
    type: 'module',
  },
  base: '/',
  scope: '/',
  filename: 'service-worker.js',
  injectManifest: {
    globIgnores: ['server/*'],
    globPatterns: ['client/**/*.{html,js,css,ico,png,svg,woff,woff2,ttf,xml,webmanifest}'],
    swSrc: './src/service-worker.ts',
  },
  injectRegister: false,
  kit: {
    outDir: '.svelte-kit',
  },
  manifest: {
    description: 'Online ordering system',
    icons: [
      ...[16, 32, 192, 194, 512].map(size => ({
        src: `favicon-${size}x${size}.png`,
        sizes: `${size}x${size}`,
        type: 'image/png',
      })),
      ...[60, 76, 120, 152, 180].map(size => ({
        src: `apple-touch-icon-${size}x${size}.png`,
        sizes: `${size}x${size}`,
        type: 'image/png',
      })),
      {
        purpose: 'maskable',
        sizes: '1333x1333',
        src: 'safari-pinned-tab.svg',
        type: 'image/png',
      },
      {
        sizes: '270x270',
        src: 'mstile-150x150.png',
        type: 'image/png',
      },
    ],
    name: 'CNYRIC Supplies',
    short_name: 'Supplies',
    theme_color: '#ffffff',
  },
  registerType: 'autoUpdate',
  srcDir: 'src',
  strategies: 'injectManifest',
  workbox: {
    navigateFallbackDenylist: [/^\/ws/, /^\/api/],
  },
} as Partial<SvelteKitPWAOptions>;

// log.debug(pwaOptions);

const config = {
  build: {
    rollupOptions: {
      external: ['node:dns/promises'],
    },
  },
  define: {
    __NODE_ENV__: process.env.NODE_ENV === 'production' ? '"production"' : '"development"',
    __APP_VERSION__: JSON.stringify(version),
  },
  plugins: [
    sentrySvelteKit({
      autoUploadSourceMaps: false,
      debug: process.env.NODE_ENV !== 'production',
      sourceMapsUploadOptions: {
        org: 'cnyric',
        project: 'supplies',
        authToken: process.env.SENTRY_AUTH_TOKEN,
      },
    }),
    sveltekit(),
    SvelteKitPWA(pwaOptions),
    watchAndRun('./src/workers', 'tsc --project tsconfig.workers.json'),
    watchAndRun(
      './main.pb.ts',
      'tsc --outDir ./pb_hooks --skipLibCheck --target es2016 --module commonjs ./main.pb.ts'
    ),
    webfontDownload([
      'https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:ital,wght@0,400;0,700;1,400;1,700&display=swap',
    ]),
    svg({
      includePaths: ['./src/lib/assets'],
      svgoOptions: {
        multipass: true,
        plugins: [
          {
            name: 'preset-default',
            params: {
              overrides: {
                removeTitle: false,
                removeViewBox: false,
              },
            },
          },
        ],
      },
    }),
  ],
  server: {
    hmr: { port: 5678 },
    proxy: {
      '/api': {
        changeOrigin: false,
        target: 'http://localhost:8090',
      },
    },
  },
  test: {
    environment: 'happy-dom',
    globals: true,
    include: ['src/**/*.{test,spec}.{js,ts}'],
  },
};

export default defineConfig(config);

svelte.config.js

import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import postcssConfig from 'postcss-load-config';
import adapter from 'sveltekit-adapter-iis';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  preprocess: [
    vitePreprocess({
      postcss: true,
      postcssConfig,
    }),
  ],
  kit: {
    adapter: adapter({ origin: process.env.ORIGIN }),
    csp: {
      directives: {
        // 'script-src': ['self', 'unsafe-eval', 'https://unpkg.com'],
      },
    },
    csrf: {
      checkOrigin: false,
    },
    files: {
      serviceWorker: 'src/service-worker.ts',
    },
    serviceWorker: {
      register: false,
    },
  },
};

export default config;

hooks.client.ts

/* region imports */
// svelte
import { dev } from '$app/environment';
import { PUBLIC_SENTRY_DSN } from '$env/static/public';

// third-party dependencies
import * as Sentry from '@sentry/sveltekit';

// internal
import { log } from '$lib/common';
import { notify } from '$lib/services/notifications';

Sentry.init({
  dsn: PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
  tracePropagationTargets: [dev ? 'localhost:5173' : /^https:\/\/supplies\.cnyric\.org/],
  profilesSampleRate: 1.0,
  environment: dev ? 'development' : 'production',
});

async function errorHandler({ error, event, status, message }) {
  if (status !== 404) {
    notify({ message, type: 'error' });
    if (dev) {
      log.debug('event', event);
      log.error(error);
    }
  }

  return {
    message,
    status,
    stack: (<Error>error)?.stack,
  };
}

export const handleError = Sentry.handleErrorWithSentry(errorHandler);

hooks.server.ts

/* region imports */
// types
import type { CookieSerializeOptions } from 'cookie';

// svelte
import { dev } from '$app/environment';
import { PUBLIC_SENTRY_DSN } from '$env/static/public';
import { redirect } from '@sveltejs/kit';

// third-party dependencies
import * as Sentry from '@sentry/sveltekit';
import { uid } from 'radashi';
import { superValidate } from 'sveltekit-superforms';
import { joi } from 'sveltekit-superforms/adapters';

// internal
import { api } from '$lib/server/api';
import { logEvent, log as logger } from '$lib/server/logger';
/* endregion imports */

/* region variables */
// constants;
const log = logger.getSubLogger({ name: 'hooks' });

/* region methods */
const validate = async (schema: any, request: any = undefined) => {
  return request ? superValidate(request, joi(schema)) : superValidate(joi(schema));
};
/* endregion methods */

Sentry.init({
  dsn: PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: dev ? 'development' : 'production',
});

async function customMiddleware({ event, resolve }) {
  const startTimer = Date.now();
  event.locals.startTimer = startTimer;
  event.locals.cookieOpts = {
    maxAge: 60 * 60 * 24 * 1, // 1 day
    path: '/',
    sameSite: 'strict',
    secure: true,
  } as CookieSerializeOptions & { path: string };
  event.locals.api = api;
  event.locals.api.authStore.loadFromCookie(event.cookies.get('auth') ?? '');

  try {
    event.locals.api.authStore.isValid && (await event.locals.api.collection('users').authRefresh());
  } catch (_) {
    event.locals.api.authStore.clear();
    return redirect(302, '/auth');
  }

  event.cookies.set('auth', event.locals.api.authStore.exportToCookie(), event.locals.cookieOpts);
  event.locals.log = log;
  event.locals.validate = validate;

  const response = await resolve(event);
  response.headers.set('Document-Policy', 'js-profiling');

  logEvent(response.status, event);
  return response;
}

export const handle = customMiddleware;

async function errorHandler({ status, error, event }) {
  if (status !== 404) {
    const errorId = uid(32);

    event.locals.error = error?.toString() || undefined;
    event.locals.errorStackTrace = (error as Error)?.stack || undefined;
    event.locals.errorId = errorId;

    logEvent(status, event);

    return {
      message: (error as Error)?.message || 'An error occurred',
      errorId,
    };
  }
}

export const handleError = Sentry.handleErrorWithSentry(errorHandler);

Steps to Reproduce

  1. Install Sentry for Sveltekit alongside VitePWA for Sveltekit
  2. Manually enable sourcemap auto-upload in vite.config.ts
  3. Build app
  4. Cry
  5. Disable sourcemap auto-upload in vite.config.ts
  6. Build app
  7. Cry a little less but cry nonetheless because you don't have readable stack traces

Expected Result

For my app to build without throwing a fit

Actual Result

$ node -r dotenv/config node_modules/vite/bin/vite.js build
Adapting with @sveltejs/adapter-node
vite v5.4.2 building SSR bundle for production...
[sentry-vite-plugin] Info: Sending telemetry data on issues and performance to Sentry. To disable telemetry, set `options.telemetry` to `false`.
✓ 1080 modules transformed.
✓ 1 webfont css downloaded. (1 ms, cache hit: 100.00%)
✓ 8 webfonts downloaded. (3 ms, cache hit: 100.00%)
x Build failed in 28.29s
error during build:
Error: The 'swSrc' file can't be read. ENOENT: no such file or directory, open '/home/dsieradski/dev/supplies/.svelte-kit/output/client/service-worker.js'
    at injectManifest (/home/dsieradski/dev/supplies/node_modules/.pnpm/[email protected]/node_modules/workbox-build/build/inject-manifest.js:70:15)
    at async Object.handler (file:///home/dsieradski/dev/supplies/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected]._z52hnnvooeeh55orrerqfguv7q/node_modules/@vite-pwa/sveltekit/dist/index.mjs:227:33)
    at async PluginDriver.hookParallel (file:///home/dsieradski/dev/supplies/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/node-entry.js:19840:17)
    at async Object.close (file:///home/dsieradski/dev/supplies/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/node-entry.js:20773:13)
    at async build (file:///home/dsieradski/dev/supplies/node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/vite/dist/node/chunks/dep-BzOvws4Y.js:65354:17)
    at async CAC.<anonymous> (file:///home/dsieradski/dev/supplies/node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/vite/dist/node/cli.js:828:5)

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugPackage: sveltekitIssues related to the Sentry SvelteKit SDK

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions