Repository navigation
SvelteKit deploy: the framework Worker packager resolves external packages with browser conditions, so @sentry/sveltekit fails to bundle #422
Description
Problem
A SvelteKit + Void app imports @sentry/sveltekit (11.7.0) in src/hooks.server.ts. vp build passes. void deploy then fails at the packaging step, before anything is uploaded:
● sveltekit framework deploy
● Found 1 migration
◇ Bundling worker...
■ Build failed with 1 error:
Error: [vite+]: Rolldown failed to resolve import "$app/stores" from
"…/node_modules/@sentry/sveltekit/build/esm/client/svelte4BrowserTracing.js".
This is most likely unintended because it can break your application at
runtime.
If you do want to externalize this module explicitly add it to
`build.rolldownOptions.external`
The void deploy --platform cloudflare packager has the same problem and gives the same error.
pg/MySQL SvelteKit apps hit it too after #413, with the same error.
The same cause can also fail without any error at build time. postgres (3.4.9) packages fine, but the packager picks its Node build. Node's net/crypto/stream become an empty stub, so the first query fails in workerd:
nodejs_als(the SvelteKit preset default):ReferenceError: Buffer is not definednodejs_als+nodejs_compat:TypeError: import___vite_browser_external.default.Socket is not a constructor
Repro
Start from playground/sveltekit (D1 + KV, @sveltejs/adapter-cloudflare 8, Kit 3).
- Add a dependency:
"@sentry/sveltekit": "11.7.0". - Add
src/hooks.server.ts:import * as Sentry from '@sentry/sveltekit'; import { sequence } from '@sveltejs/kit/hooks'; export const handle = sequence( Sentry.initCloudflareSentryHandle({ dsn: 'https://public@example.invalid/1', tracesSampleRate: 1 }), Sentry.sentryHandle(), ); export const handleError = Sentry.handleErrorWithSentry();
- Run:
For the native path, call
vp build # passes void deploy --skip-build # fails at "Bundling worker..."
prepareCfFrameworkBuildOutput(void deploy --platform cloudflareruns it as a preflight) on the same build. It fails with the same error.
Cause
Kit's server build leaves @sentry/sveltekit as a bare import (.svelte-kit/output/server/entries/hooks.server.js: import * as Sentry from "@sentry/sveltekit"). Void then bundles the adapter's _worker.js with a Vite lib build. That build has no ssr and no resolve.conditions, so Vite uses its client environment, with conditions ["module","browser","development|production"].
vp build (Kit + adapter-cloudflare)
└─ .svelte-kit/cloudflare/_worker.js ──> hooks.server.js ──> "@sentry/sveltekit" (external)
│
void deploy void deploy --platform cloudflare
runFrameworkDeploy prepareCfFrameworkBuildOutput
bundleEntry (wrapper.ts:520) prepareBundledBuildOutput (cf-build-output.ts:205)
└──── vite build({ build: { lib } }) → client env, "browser" condition ────┘
│
@sentry/sveltekit → build/esm/index.client.js → … → client/svelte4BrowserTracing.js
└─ import "$app/stores" ✗ (exists only inside Kit's build)
Code (on main, b58300f):
packages/void/src/cli/preset.ts:115-124: thesveltekitpreset setsbundle: true(:123). It is the only preset that does.packages/void/src/cli/deploy-managed-framework.ts:133-135: the hosted deploy callsbundleEntry(root, originalEntry).packages/void/src/cli/wrapper.ts:520-553:bundleEntryrunsbuild({ root, build: { lib: { entry, formats: ['es'] }, … } })and sets no conditions.packages/void/src/cli/deploy-cloudflare-build.ts:326-336: the native deploy runsprepareCfFrameworkBuildOutputfor everyworker-outputpreset (SvelteKit, Nuxt, Analog, Astro), as a preflight before remote changes. Only SvelteKit was tested.packages/void/src/cli/cf-build-output.ts:205-229:prepareBundledBuildOutputis the same kind of lib build (configFile: false,libat:225).packages/void/src/plugin-framework.ts:280-321: for pg/MySQL, thevoid:sveltekit-worker-buildplugin moves onlyvoid,drizzle-orm, the driver and packages that importvoidinto Kit's workerd build. "Other dependencies stay external" (:287), so they still reach the browser-condition packager.
@sentry/sveltekit@11.7.0 package.json → exports["."]:
{
"types": "./build/types/index.types.d.ts",
"workerd": { "import": "./build/esm/index.workerd.js", "require": "./build/cjs/index.workerd.js" },
"worker": { "import": "./build/esm/index.worker.js", "require": "./build/cjs/index.worker.js" },
"browser": { "import": "./build/esm/index.client.js", "require": "./build/cjs/index.client.js" },
"node": { "import": "./build/esm/index.server.js", "require": "./build/cjs/index.server.js" },
"default": { "import": "./build/esm/index.server.js", "require": "./build/cjs/index.server.js" }
}With the client conditions, only browser matches, so the import resolves to index.client.js. That file is browser code: it pulls in Kit's $app/* modules and does not export initCloudflareSentryHandle or sentryHandle.
postgres@3.4.9 exports["."] is { "workerd": "./cf/src/index.js", "import": "./src/index.js", … }. The client conditions skip workerd and match import, which is the Node build.
Check: the same bundleEntry options plus only resolve.conditions: ['workerd','worker','browser','module','import','default']:
@sentry/sveltekitresolves toindex.workerd.js. The build passes, and the Worker returns 200 for/in Miniflare withnodejs_als.postgresresolves tocf/src/index.js. The query reaches a real socket connect.
Suggested fix
Give both lib builds Worker resolve conditions. wrapper.ts:315-316 already defines WORKER_CONDITIONS and uses it for the SQL driver bundle (wrapper.ts:353-357). Use it in bundleEntry and prepareBundledBuildOutput (resolve: { conditions: WORKER_CONDITIONS }). prepareCfStaticBuildOutput (cf-build-output.ts:256) shares prepareBundledBuildOutput, so it gets the same change. Add a regression test with a fixture package that has both browser and workerd exports, and check that the packaged Worker uses the workerd file.
🤖 Generated with Claude Code
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Activity