| 1 | --- |
| 2 | title: 2.0.0-beta.44 - Config & Bundle Analyzer |
| 3 | date: 2026-05-22T20:00:00Z |
| 4 | category: release |
| 5 | excerpt: v2.0.0-beta.44 adds a new `Cloudflare.Zaraz.Config` resource, a bundle analyzer for Workers, and Artifacts binding support in dev, plus a handful of bundler and dev-server fixes. |
| 6 | --- |
| 7 | |
| 8 | `v2.0.0-beta.44` is a polish release. Two new things worth |
| 9 | calling out — a new **`Cloudflare.Zaraz.Config`** resource and a |
| 10 | **bundle analyzer plugin** for the Worker bundler — plus a |
| 11 | batch of bundler and dev-server fixes. |
| 12 | |
| 13 | ## `Cloudflare.Zaraz.Config` |
| 14 | |
| 15 | New resource for managing a zone's Zaraz config — tools, |
| 16 | triggers, variables, consent, analytics, and workflow mode — |
| 17 | declaratively alongside the rest of your Cloudflare stack. |
| 18 | |
| 19 | ```typescript |
| 20 | import * as Cloudflare from "alchemy/Cloudflare"; |
| 21 | |
| 22 | const zaraz = yield* Cloudflare.Zaraz.Config("analytics", { |
| 23 | zone: "example.com", |
| 24 | tools: { |
| 25 | "google-analytics": { /* tool config */ }, |
| 26 | }, |
| 27 | consent: { enabled: true }, |
| 28 | }); |
| 29 | ``` |
| 30 | |
| 31 | A couple of design notes worth knowing: |
| 32 | |
| 33 | - Fields you omit (`tools`, `triggers`, `variables`, `workflow`) |
| 34 | are **left alone** rather than wiped. This means you can adopt |
| 35 | a zone's existing Zaraz setup incrementally. |
| 36 | - Destroy is **opt-in** via `delete: true`. By default, |
| 37 | destroying the resource removes it from Alchemy state and |
| 38 | leaves the zone's Zaraz config intact. With `delete: true`, |
| 39 | destroy restores Cloudflare's defaults (including resetting |
| 40 | `workflow` to real-time mode). |
| 41 | - Typed Zaraz event helpers ship as `defineZarazEvents`. |
| 42 | |
| 43 | Thanks **[Alex](https://github.com/agcty)** for the |
| 44 | contribution. |
| 45 | ([#371](https://github.com/alchemy-run/alchemy/pull/371)) |
| 46 | |
| 47 | ## Bundle analyzer for Workers |
| 48 | |
| 49 | The Worker bundler can now emit a per-build report describing |
| 50 | exactly what ended up in your bundle: chunks, modules, the |
| 51 | import graph reachable from each entry point, and which entry |
| 52 | pulled in which module. |
| 53 | |
| 54 | Opt in via `build.bundleAnalyzer` on the Worker: |
| 55 | |
| 56 | ```diff lang="typescript" |
| 57 | export default class Api extends Cloudflare.Worker<Api>()( |
| 58 | "Api", |
| 59 | { |
| 60 | main: import.meta.filename, |
| 61 | + build: { bundleAnalyzer: true }, |
| 62 | }, |
| 63 | /* ... */ |
| 64 | ) {} |
| 65 | ``` |
| 66 | |
| 67 | By default this writes `analyze-data.md` next to the bundle in `.alchemy/bundles/<id>`. |
| 68 | Pass an object to customize: |
| 69 | |
| 70 | ```typescript |
| 71 | build: { |
| 72 | bundleAnalyzer: { fileName: "bundle.json", format: "json" }, |
| 73 | } |
| 74 | ``` |
| 75 | |
| 76 | Under the hood it wraps rolldown's experimental |
| 77 | `bundleAnalyzerPlugin`, exported as `Bundle.bundleAnalyzerPlugin` |
| 78 | for anyone composing their own bundles. |
| 79 | ([#405](https://github.com/alchemy-run/alchemy/pull/405)) |
| 80 | |
| 81 | This replaces the previous `build.metafile` option, which is now removed. |
| 82 | |
| 83 | ## `Cloudflare.Artifacts.Artifacts` in dev |
| 84 | |
| 85 | The `Cloudflare.Artifacts.Artifacts` binding now works under |
| 86 | `bun alchemy dev` — previously it was only wired up in deployed |
| 87 | Workers. No code change required; existing artifact bindings |
| 88 | light up locally on upgrade. |
| 89 | ([#419](https://github.com/alchemy-run/alchemy/pull/419)) |
| 90 | |
| 91 | ## `RpcProvider` for more reliable local development |
| 92 | |
| 93 | Until beta.43, local providers (the runtime that backs |
| 94 | `Cloudflare.Worker`, `DurableObject`, etc. under |
| 95 | `alchemy dev`) ran inside an in-process "sidecar" tied to the |
| 96 | dev server. That worked, but it leaked: when the dev process |
| 97 | exited — Ctrl-C, crash, HMR restart — the child `workerd` |
| 98 | processes it had spawned could survive, holding ports |
| 99 | open and consuming memory until you noticed and killed them by |
| 100 | hand. |
| 101 | |
| 102 | beta.44 refactors this into a generic `Local/Rpc*` provider |
| 103 | abstraction. Local providers now run in their own child process |
| 104 | managed by a new `RpcSpawner`, and the parent talks to them |
| 105 | over RPC. Concretely: |
| 106 | |
| 107 | - It registers an `exitHook` that `SIGKILL`s the entire process |
| 108 | group when the parent exits, plus a scoped finalizer for the |
| 109 | graceful path. Dangling `workerd` processes are gone. |
| 110 | - Sessions are cached per |
| 111 | `(serverEntryUrl, alchemyContext, stack)` and respawned |
| 112 | automatically if the child dies mid-session. |
| 113 | - `RpcProvider.providerServicesEffect` lets heavy provider-only |
| 114 | layers (e.g. the Cloudflare local runtime and proxy) build |
| 115 | lazily inside the child rather than eagerly in the parent — |
| 116 | the parent stays lean. |
| 117 | |
| 118 | The defining shape for a provider is now thin: |
| 119 | |
| 120 | ```typescript |
| 121 | export const LocalWorkerProvider = () => |
| 122 | RpcProvider.effect( |
| 123 | Worker, |
| 124 | import.meta.resolve(/* ./Local.ts | ./Local.js */), |
| 125 | Effect.gen(function* () { /* … */ }), |
| 126 | ); |
| 127 | ``` |
| 128 | |
| 129 | ## Also in this release |
| 130 | |
| 131 | - **Vite-style `?raw` imports in the Worker bundler** — |
| 132 | `import sql from "./schema.sql?raw"` now works, matching the |
| 133 | Vite convention for inlining a file as a string |
| 134 | ([#411](https://github.com/alchemy-run/alchemy/pull/411)). |
| 135 | - **Local Durable Objects hardened** — fixes swapped |
| 136 | `className`/`namespaceId` in the local provider output, makes |
| 137 | the local `namespaceId` deterministic and independent of the |
| 138 | binding name, and stops DOs declared on other Workers in the |
| 139 | stack from being registered against the current Worker |
| 140 | ([#408](https://github.com/alchemy-run/alchemy/pull/408)). |
| 141 | - **`alchemy dev` now honors your Workers `assets` config** — |
| 142 | the configured asset behavior was previously ignored in local |
| 143 | dev |
| 144 | ([#403](https://github.com/alchemy-run/alchemy/pull/403)). |
| 145 | - **`mysql2` no longer errors at bundle time** in the Worker |
| 146 | bundler |
| 147 | ([#403](https://github.com/alchemy-run/alchemy/pull/403)). |
| 148 | - **`x-forwarded-for` and `x-forwarded-proto` headers** are now |
| 149 | forwarded on incoming requests in `alchemy dev` |
| 150 | ([#403](https://github.com/alchemy-run/alchemy/pull/403)). |
| 151 | - **Rolldown bumped to 1.0.1 stable** — out of pre-release |
| 152 | ([#409](https://github.com/alchemy-run/alchemy/pull/409)). |
| 153 | - **`@alchemy.run/node-utils` import resolution fix** — resolves |
| 154 | an ESM resolution error on Node |
| 155 | ([#406](https://github.com/alchemy-run/alchemy/pull/406)). |
| 156 | - **CLI filters Bun's "not in project directory" watcher warning** — |
| 157 | no more spurious warnings during dev. Thanks |
| 158 | **[Michael K](https://github.com/michaelkleene)** |
| 159 | ([#124](https://github.com/alchemy-run/alchemy/pull/124)). |
| 160 | |
| 161 | ## Contributors |
| 162 | |
| 163 | Thanks to everyone who shipped code in this beta: |
| 164 | |
| 165 | - **[Alex](https://github.com/agcty)** — `Cloudflare.Zaraz.Config` ([#371](https://github.com/alchemy-run/alchemy/pull/371)) |
| 166 | - **[Michael K](https://github.com/michaelkleene)** — CLI watcher warning filter ([#124](https://github.com/alchemy-run/alchemy/pull/124)) |
| 167 | - **[sam](https://github.com/samgoodwin)** — privacy page styling cleanup ([#398](https://github.com/alchemy-run/alchemy/pull/398)) |
| 168 | |
| 169 | ## Where to go next |
| 170 | |
| 171 | - [CHANGELOG](https://github.com/alchemy-run/alchemy/blob/main/CHANGELOG.md#v200-beta44) |
| 172 | - [Compare v2.0.0-beta.43 → v2.0.0-beta.44](https://github.com/alchemy-run/alchemy/compare/v2.0.0-beta.43...v2.0.0-beta.44) |