fix(bundle): resolution fixes - #1091
Conversation
workerd supplies `cloudflare:workers` at runtime; it has no filesystem
existence. Rolldown resolves imports before tree-shaking, so any bundled
graph referencing it trips [UNRESOLVED_IMPORT] even where a runtime guard
makes the import dead code.
The CLI's dev executable reaches `cloudflare_workers.ts`, whose guarded
`import("cloudflare:workers")` falls back to a stub off workerd. A
cross-provider Lambda can reach it too, and a Lambda can never resolve the
module — keeping it external lets the runtime fallback handle it.
A virtual entry has no filesystem location, and Alchemy's bundled runtime entries reference private `@distilled.cloud/*` packages the consumer never depends on. Resolving either through the consumer's package graph only worked when the package manager happened to hoist those dependencies. Peer dependencies such as Effect are deliberately left alone: they must keep resolving from the consumer's graph so the runtime has a single Effect identity.
9047a91 to
9d298bd
Compare
| // dynamic import of workerd's virtual module. A Lambda can never | ||
| // resolve it; keep the import external so the runtime fallback | ||
| // handles it instead of tripping [UNRESOLVED_IMPORT] before DCE. | ||
| if (moduleId === "cloudflare:workers") return true; |
| const ENTRY_PREFIX = "\0virtual:alchemy-entry:"; | ||
| // oxlint-disable-next-line no-control-regex | ||
| const ENTRY_REGEX = /^\0virtual:alchemy-entry:/; | ||
| const ALCHEMY_PRIVATE_DEPENDENCY_REGEX = /^@distilled\.cloud\//; |
There was a problem hiding this comment.
These are not all private. All the distilled SDKs are in there. What motivated this?
There was a problem hiding this comment.
Fair — "private" is the wrong word; they're published. The intent is provenance, not privacy: resolve @distilled.cloud/* from alchemy's own install rather than the consumer's package graph.
What motivated it: I consume alchemy in another monorepo from a packed tarball built off a worktree carrying my open PRs plus distilled patches that aren't on npm yet. (bun link isn't workable there — linking pulls alchemy's whole source tree into the dev server's watch graph, >10k files, and the process hits the macOS open-file limit.) The patched SDK builds ride inside alchemy's install, so bundled user code has to resolve @distilled.cloud/* to those copies — the consumer graph either doesn't have them or hoists the unpatched registry versions.
It's not specific to that workflow though: imports reached from the virtual entry have no importer path, so without the plugin resolution falls back to the consumer graph and only works when the package manager happens to hoist — and the versions it hoists aren't necessarily the ones alchemy's install was built against.
The @distilled.cloud packages are published SDKs, not private. The plugin is about provenance — bundled user code gets exactly the SDK versions this installation of alchemy carries — so name and comment now say that.
Two fixes to what the bundler resolves.
cloudflare:workersis supplied by workerd and has no filesystem existence, but rolldown resolves imports before tree-shaking — so any bundled graph referencing it fails with[UNRESOLVED_IMPORT]even where a runtime guard makes the import dead code. The CLI's dev executable reachescloudflare_workers.ts(whose guardedimport("cloudflare:workers")falls back to a stub off workerd), and a cross-provider Lambda can reach it too — a Lambda can never resolve the module, so keeping it external lets the runtime fallback handle it. Worker bundles already get this from the cloudflare rolldown plugin.defineConfig({ entry: ["bin/exec.ts"], + external: ["cloudflare:workers"],Alchemy's SDK dependencies (
@distilled.cloud/*) resolve from alchemy's own installation instead of the consumer's package graph, which only worked when the package manager happened to hoist them:Peers like Effect are deliberately not handled — they must resolve from the consumer so the runtime has a single Effect identity. An id alchemy's own install cannot resolve falls through to normal resolution.