Patch Changes
-
#1334
77c8c9cThanks @threepointone! -createWorkerandcreateAppnow accept a handful of extra esbuild knobs that previously required forking or patching the package:jsx("transform" | "preserve" | "automatic")jsxImportSourcedefine(compile-time constant replacement)loader(per-extension loader overrides — e.g.{ ".svg": "text", ".wasm": "binary" }; built-in handling for.ts/.tsx/.js/.jsx/.json/.cssis preserved unless overridden, and longer extensions match first so".d.ts"wins over".ts"). The accepted values are deliberately narrowed to the portableBundlerLoaderset (js/jsx/ts/tsx/json/css/text/binary/base64/dataurl) — esbuild-specific loaders likefile/copy/empty/defaultare intentionally excluded.file/copywould silently break in this bundler today (they emit secondary output files that get discarded), and anything outside the portable set should go through the plugin escape hatch instead.conditions(package export conditions, e.g.["workerd", "worker", "browser"])
The first five are re-typed locally (
JsxMode,BundlerLoader) so the published.d.tsdoes not import fromesbuild-wasm— a future bundler swap is a refactor, not a breaking type change.For advanced consumers (RSC-style transforms, custom asset pipelines, codegen) there is also an explicit escape hatch:
__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired?: unknown[]
The deliberately unwieldy name is the API contract: this option is not covered by semver, can change shape or be removed in any release, and ties the caller to esbuild's plugin shape — if this package switches bundlers, plugins authored against it will break. It is typed as
unknown[]at the public boundary (castPlugin[]fromesbuild-wasmwhen passing in) so the published types don't acquire a hard dependency on esbuild. User plugins run before the internal virtual-filesystem plugin, so theironResolve/onLoadclaims fire first.In
createApp, all of these options apply to both the server and client bundles.The internal
bundleWithEsbuildsignature was refactored from a long positional argument list to a single options object so future bundler knobs can be added without churning every call site. This is an internal change; no public API moved.Inspired by #1321 — thanks @bndkt for the draft and the RSC-on-Workers proof-of-concept that motivated it.
-
#1335
e59388dThanks @threepointone! - Fix: don't crash withCannot find package 'gojs'when imported from Node.Previously,
bundler.tsdid a top-level staticimport esbuildWasm from "./esbuild.wasm". In the Workers runtime that resolves to aWebAssembly.Modulenatively, but in Node 22+ (e.g. Vitest on GitHub Actions CI) Node's experimental ESM-WASM loader actually parses the file and tries to resolveesbuild-wasm's Go-runtime import namespacegojsas an npm package. That surfaced as the deeply confusing error reported in #1306:Cannot find package 'gojs' imported from .../@cloudflare/worker-bundler/dist/esbuild.wasmTwo changes:
- The
./esbuild.wasmimport is now lazy — it lives insideinitializeEsbuild()as a dynamicimport("./esbuild.wasm")call instead of a module-level static import. The package is now safely importable from any JavaScript runtime. - Before evaluating that dynamic import, the bundler checks
navigator.userAgent === "Cloudflare-Workers". If it's not running inside workerd, it throws an actionable error pointing the caller at@cloudflare/vitest-pool-workersinstead of letting Node surface the crypticgojsresolution failure.
A side benefit:
createWorker({ bundle: false })(transform-only mode, which never invokes esbuild) now also works in Node, because the WASM is never loaded on that code path.The README now also calls out the Workers-only requirement near the top.
While in there, sharpened a handful of unhelpful error messages to include actionable context:
- "Entry point/Server entry point/Client entry point ... not found" now lists the user-provided files in the bundle (skipping
node_modules/) so it's obvious whether the path is mistyped vs. missing entirely. - "Could not determine entry point" now spells out the full priority list it tried (
entryPointoption → wranglermain→package.json→ defaults). - npm registry errors include the package name, version, registry URL, and HTTP status text — e.g.
Registry returned 404 Not Found for "hno" at https://registry.npmjs.org/hno (package not found — check the name in package.json or set theregistryoption if it lives on a private registry). - The npm fetch-timeout error names the URL and notes the registry was slow/unreachable from the Worker.
- "Invalid package.json" includes both the path and the underlying parse error.
- "No output generated from esbuild" now names the entry point and explains the two real-world causes (a custom plugin claiming the entry without returning contents, or the entry resolving to an externalised module).
- The