Compile and target Cloudflare Workers
Goal: understand the two emission targets and build a deployable Worker.
bynkc compile takes a --target:
| Target | Flag | What it emits | Cross-context calls |
|---|---|---|---|
| Bundle | --target bundle (default) | A flat TypeScript tree mirroring your source | Direct in-process calls |
| Workers | --target workers | One Cloudflare Worker per context | JSON calls over Service Bindings, validated at the boundary |
Bundle (default)
Section titled “Bundle (default)”bynkc compile . --output outEach source unit becomes a .ts file, and contexts call each other directly.
Use this for a single deployable unit or for running the output yourself.
Workers
Section titled “Workers”bynkc compile . --output out --target workersEach context becomes a directory under out/workers/<context>/:
out/workers/notes/├── handlers.ts # your handler logic├── index.ts # the Worker entry point + router├── compose.ts # dependency wiring└── wrangler.toml # Cloudflare configA workers build is the deployable, so it writes no test modules: every suite
is stripped (bynkc test compiles and stages them itself).
The emitted directory is a standard Worker. Run it locally with Wrangler:
cd out/workers/notesnpx wrangler devOr, in one step:
bynk devdoes this whole recipe for you — compile, pick the worker, andwrangler dev— from anywhere inside the project, with nothing to provision. The manual flow above is what it runs under the hood.
An
from httpservice only produces a runnable Worker on theworkerstarget. A stateful agent compiles to a Durable Object there; onbundlethe same agent uses an in-process state registry instead.
When a handler faults
Section titled “When a handler faults”A fault in an HTTP route, an on call service, an event delivery or a
WebSocket upgrade answers a 500 Internal Server Error. The client never sees the error. The Worker logs it first, with
console.error, so it shows in wrangler tail and the Workers logs:
shop.api GET /shout/:word faulted Error: provider exploded for boom at Object.shout (index.js:412:11) …The line names the context and the dispatch that faulted: the route’s
pattern, call <service> for a service call, event <service> for an event
delivery, or ws <service> for a WebSocket upgrade. It never names the
request, so no key or value from the URL reaches the log. A queue consumer
logs queue <name> threw and retries the message.
Both log the error’s stack, not only its message. The frames in that line
stay in the bundle’s own coordinates (index.js:412:11): a stack the Worker
logs is a plain string, which Cloudflare never rewrites.
So the Worker also reports the fault to Cloudflare, without changing its
answer: the client still gets the 500, and a queue message is still retried.
wrangler tail and the Workers logs then show the fault a second time, as the
invocation’s exception. If you deploy with
wrangler deploy --upload-source-maps (bynk deploy -- --upload-source-maps),
that exception’s stack is mapped to your .bynk lines:
Error: provider exploded for boom at Provider.shout (../../provider.binding.ts:6:13) at Object.http_GET_shout_Param_word (../../../../src/shop/api.bynk:14:5) …The frames name the file each was compiled from, relative to the Worker’s
build directory: a .bynk file for your handlers, and the binding’s own
TypeScript when the fault was thrown inside it.
A faulted request keeps its ok outcome, since it was answered. A faulted
queue delivery is counted as an exception, though the message is still retried
one at a time, never the whole batch.
To step through a fault rather than read its stack, reproduce it under
bynk dev --inspect:
attach a debugger, turn on pausing on caught exceptions, and send the request
again.
A refused cross-context call is also logged by name on both sides: see Contract skew.
Related
Section titled “Related”- Tutorial: Build a small HTTP service.
- Consume another context’s services with
consumes. - Reference: emission.