Skip to content

Worker bundler: default-on pure annotations break pre-bundled effect inputs at runtime #589

Description

@agcty

Symptom (2.0.0-beta.55)

A StaticSite whose main is an already-complete vite server bundle (React Router RSC app, effect-based request handling) deploys fine, but every request on the deployed Worker dies with:

TypeError: _(...).then is not a function
    at MixedScheduler.<anonymous> (Schema-<hash>.js:14:4727)

The same code is healthy under vite dev and in the vite build itself — the failure is introduced by the Worker upload re-bundle. Setting build: { pure: false } fixes it deterministically.

Cause (corrected)

My first read of this was that the pure plugin was matching the effect/@effect/* packages on the pre-bundled input. That is not what happens, and it's worth correcting because it points at the real fix.

purePlugin matches by package name resolved from the module's path, not by anything in the code: resolvePackageInfo walks up to the nearest package.json and packageNameFromId reads the node_modules/<pkg> segment (PurePlugin.ts ~L120-121, L270-282, L294-366). In a vite/rolldown output (build/server/index.js + build/server/assets/*.js) the effect package boundaries no longer exist — walking up from any chunk lands on the app's own package.json, not effect. So the effect/@effect/* patterns never fire on this input.

What actually fires is autoDetectEntryPackage (default true, PurePlugin.ts L72/L91/L107-116): it detects the entry's owning package and adds it to the match set. The app package declares "sideEffects": false, so:

  • every chunk under build/server/ resolves to that one owning package and matches, and
  • because sideEffects is false, the plugin applies both /*#__PURE__*/ annotations and moduleSideEffects: false (PurePlugin.ts L133-145) across the whole pre-bundled output.

Marking an already-bundled vite artifact side-effect-free / pure lets rolldown drop top-level initializers the effect scheduler dereferences at request time — hence the per-request TypeError. build: { pure: false } disables the whole plugin, which is why it's a clean fix.

So the trigger is autoDetectEntryPackage + the app package's sideEffects: false, applied to a pre-bundled multi-chunk input — not effect-package matching.

Suggestions

  1. Behavior: when the bundle entry resolves into a build-output directory (chunk-shaped input / existing sourcemap), autoDetectEntryPackage shouldn't auto-annotate it — the owning package.json's sideEffects: false describes the source tree, not a foreign bundler's already-emitted output. Defaulting auto-detect off for that input class (or for StaticSite/main-points-at-artifact specifically) would avoid the foot-gun.
  2. Docs: at minimum, document the failure mode on BundleExtraOptions.pure / autoDetectEntryPackage — the current jsdoc describes the mechanism but not that feeding a pre-bundled input through it can drop runtime-needed initializers and 500 every request.

(For context: the idiomatic path for a vite app is Cloudflare.Vite, which bundles source itself and never re-bundles a foreign artifact — so this only bites when main is pointed at a pre-built bundle. The report stands as a sharp-edge in that configuration plus a docs gap.)

Happy to PR whichever direction you prefer (same fork as #586/#587).

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions