Skip to content

@sentry/sveltekit: server entry statically re-exports the Vite plugin, pulling @babel/core into the runtime module graph #23243

Description

@MathiasWP

Summary

@sentry/sveltekit's server entry point statically re-exports the Vite build plugin, so importing the SDK in server code instantiates and evaluates the entire build-time module graph — including @babel/core and ~200 of its files.

This is deliberately not a request to move @sentry/vite-plugin out of dependencies — I've read #19360 and #18215 and understand the one-package decision. This is the narrower follow-up to what @Lms24 wrote in #19360:

Our Vite plugin should not be used at runtime and hence not be pulled into any JS bundles executed at runtime. If that's the case, it's likely a bug we need to fix.

It is pulled in, and the mechanism is a single static re-export.

The chain

build/esm/index.server.js:2 — the Node/default condition entry:

export { trackComponent } from './server/index.js';
export { sentrySvelteKit } from './vite/sentryVitePlugins.js';   // <-- build plugin, from the runtime entry
export * from '@sentry/node';

From there every link is a top-level static ESM import:

build/esm/index.server.js:2      export { sentrySvelteKit } from './vite/sentryVitePlugins.js'
build/esm/vite/sentryVitePlugins.js:7  import { makeCustomSentryVitePlugins } from './sourceMaps.js'
build/esm/vite/sourceMaps.js:3   import { sentryVitePlugin } from '@sentry/vite-plugin'
@sentry/vite-plugin  index.mjs:3 import { sentryCliBinaryExists } from '@sentry/bundler-plugin-core'
@sentry/bundler-plugin-core index.mjs:1  import { transformAsync } from '@babel/core'

Because these are static re-exports rather than lazy imports, they are part of the module graph and get evaluated when the entry is evaluated — no call to sentrySvelteKit() required.

Measurement

Node v24.15.0, macOS, pnpm 11.16.0, 3 runs each. cjs counts require.cache keys after the dynamic import resolves:

import time CJS modules loaded of which @babel/*
@sentry/node (ESM entry) 2.8 – 3.2 s 168 0
@sentry/sveltekit (server entry) 4.0 – 5.0 s 392 201

Repro:

// probe.mjs, run with: node probe.mjs
import { createRequire } from 'node:module';
const require = createRequire(process.cwd() + '/');
await import('@sentry/sveltekit');
const loaded = Object.keys(require.cache);
console.log(loaded.length, loaded.filter((p) => p.includes('/@babel/')).length);
// -> 392 201

The absolute timings are from a laptop and won't transfer to a serverless runtime, but the module counts are deterministic.

Impact we observed

With @sveltejs/adapter-vercel, SvelteKit leaves @sentry/sveltekit unbundled in the server output — it survives as a single bare from "@sentry/sveltekit" import in the chunk our logger lives in, and the logger is imported by essentially every repository and service. @vercel/nft then traces that specifier and, because it traces files rather than symbols, copies the whole reachable graph into the serverless function:

  • 156 packages / 2,743 files / 22 MB in a single .func, including @babel/core, @babel/traverse, @babel/parser, @babel/generator, @babel/types, caniuse-lite (via babel's browserslist), acorn and @sentry/bundler-plugin-core
  • those 201 Babel files are then loaded on every cold start, per the measurement above

Note this is the outcome @Lms24 suggested in #19360 as the mitigation ("use tools like @vercel/nft to prune your runtime node modules") — nft is already what runs here, and it can't help, because the reachability is real rather than incidental.

Suggested fix

Move sentrySvelteKit off the runtime entry, e.g. to a dedicated @sentry/sveltekit/vite export used from vite.config.ts. That keeps the one-package installation story intact (no new package to publish, no version-skew risk) while keeping the build plugin out of the runtime graph.

If a breaking change to the . export isn't desirable, exposing it via a lazy accessor rather than a static re-export would also break the static edge.

Environment

  • @sentry/sveltekit 10.69.0
  • @sveltejs/kit 2.70.2, @sveltejs/adapter-vercel 6.3.4, svelte 5.56.8, vite 8.2.0
  • Node v24.15.0, pnpm 11.16.0

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions