@sentry/cloudflare/vite: Auto-instrumentation skips the Worker when wrangler `main` is a package specifier

Open
#24,522 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
58/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript, vite

Research direction

Start with packages/cloudflare/src/vite/wranglerConfig.ts, autoInstrument.ts, and instrumentFile.ts, then inspect the existing Cloudflare Vite test fixtures. Trace how Wrangler's main value is resolved and compared with transformed module IDs. Done means package-specifier entries are instrumented, node_modules entries find the project instrument file, unmatched entries produce a warning, and a package-specifier fixture passes.

Written by the indexing model from the issue text.

Description

Cloudflare Workers Feature
Description

sentryCloudflareVitePlugin() does not wrap the Worker when main in the Wrangler config is a package specifier and not a file path. The build succeeds, but the bundle contains no Sentry code, and the plugin logs no warning.

@cloudflare/vite-plugin supports this config, and vinext generates it by default with vinext init --platform=cloudflare:

// wrangler.jsonc
{
  "main": "vinext/server/fetch-handler",
  // ...
}
// vite.config.ts
export default defineConfig({
  plugins: [
    vinext(),
    cloudflare({ viteEnvironment: { name: "rsc", childEnvironments: ["ssr"] } }),
    sentryCloudflareVitePlugin(),
  ],
});

Tested with @sentry/cloudflare@11.0.0-rc.0, @cloudflare/vite-plugin@1.56.0, wrangler@4.135.0, vinext@1.0.0-beta.10 and Vite 8.3.

Cause

resolveWranglerConfig() calls unstable_readConfig() without preserveOriginalMain (wranglerConfig.ts#L70). Wrangler then resolves every main as a path relative to the config file:

main: "vinext/server/fetch-handler"
-> <project>/vinext/server/fetch-handler   (file does not exist)

autoInstrument.ts compares this path with the module IDs in transform (L75), so no module matches. resolveInstrumentFile() also looks for instrument.server.* in the directory of this path (instrumentFile.ts#L23), and a package entry has no such file.

@cloudflare/vite-plugin handles the same value differently:

  1. It reads the config with unstable_readConfig(..., { preserveOriginalMain: true }).
  2. maybeResolveMain() makes main absolute only when it ends with a JS or TS extension.
  3. It resolves the entry with Vite: await this.resolve(workerConfig.main).
Workaround

Add a local entry that re-exports the package entry, and set main to it. Put instrument.server.ts in the same directory:

// worker/index.ts
import handler from "vinext/server/fetch-handler";

export default handler;
{ "main": "./worker/index.ts" }
Proposed fix
  • Read the config with preserveOriginalMain: true, and keep a package specifier unchanged.
  • Resolve main with this.resolve() (for example in buildStart, or lazily in transform), and compare the resolved module ID.
  • When the resolved entry is in node_modules, look for instrument.server.* in the Wrangler config directory (the Vite root) and not next to the entry.
  • Log a warning when main does not resolve to a module that the plugin transforms, so the failure is not silent.
  • Add a test fixture where main is a package specifier.
Dominant language
TypeScript
Stars
8.7k
Forks
1.9k
Avg merge
1d 18h
Merged PRs (30d)
543

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from getsentry/sentry-javascript

All issues in getsentry/sentry-javascript

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.