fix(supabase): shrink Edge Function deploy 314MB→8MB via pre-bundled adapter + import-map redirect#5366
Conversation
ReviewThis PR shrinks the Supabase Edge Function deploy by pre-bundling Overall this is a well-reasoned fix with good measurement in the PR description. One structural concern surfaced from tracing the actual module graph:
Tracing the static import graph from This means the actual invariant this whole PR depends on is "rivetkit-core's dynamic imports of these native packages stay non-literal/obfuscated," and that invariant isn't asserted anywhere. If a future change to Neither of this PR's two new guards would catch that regression before it reaches a user's deploy:
Worth considering a guard that directly asserts the thing that matters: grep the built Minor
Nothing else surfaced that looked like a live bug. The dependency reshuffling in |
95afa32 to
fb63356
Compare
|
🚅 Deployed to the rivet-pr-5366 environment in rivet-frontend
|
fb63356 to
a6c7339
Compare
a6c7339 to
ef9730e
Compare
ef9730e to
e115953
Compare
e115953 to
b06e8d0
Compare
b06e8d0 to
c6cd3c1
Compare
c6cd3c1 to
fe26d34
Compare
fe26d34 to
0aa573b
Compare
0aa573b to
af1d3da
Compare
|
Parking this to prioritize slimming the engine binary/frontend first (the engine binary is ~70% embedded dashboard, ~47% sourcemaps). Branch |
af1d3da to
47c7ce4
Compare
…ee edge deploy) + edge bundle-budget CI + docs; regen stale BARE codecs
47c7ce4 to
14a9ad2
Compare
Problem
Deploying a trivial state-only RivetKit actor to Supabase Edge Functions produces a ~314 MB Deno eszip and fails with HTTP 413. Supabase's
edge-runtime bundlesnapshots the entire declared npm dependency closure (not the reachable import graph), so importingrivetkitdrags in its native packages —@rivetkit/engine-cli(~117 MB engine binary),@rivetkit/rivetkit-napi(~74 MB), and@rivet-dev/agent-os-core(secure-exec V8) — none of which the wasm runtime ever executes. That's ~245 MB (78%) of native ELF the edge deploy can't use.Fix — pre-bundled adapter + import-map redirect (no source API change)
@rivetkit/supabasenow bundles rivetkit's wasm-path code into its own dist and re-exports the authoring API (export * from "rivetkit"), declaring only@rivetkit/rivetkit-wasm(pluspino/cbor-x) at runtime — never the native packages.deno.jsonimport map points"rivetkit"→@rivetkit/supabase. User source staysimport { actor } from "rivetkit"; Deno just resolves it to the native-free adapter.rivetkititself is unchanged → the Node / native runtime path is unaffected (zero regression).Two Deno-bundling issues fixed along the way: pino's dynamic
require("os")(kept external so Deno node-compat loads it), and unprefixed Node builtin imports (esbuild plugin rewrites them tonode:).Result (measured with Supabase's exact bundler; deployed + booting)
from "rivetkit"Approaches measured and rejected:
devDependencies(33 MB but breaks Node),optionalDependencies(619 MB — Deno snapshots optionals), exportconditions(617 MB — conditions pick the entry module, not the installed deps).Guard rails — CI job
RivetKit / Edge Bundle BudgetThe edge deploy can regress two independent ways; the job guards both (plus a size budget):
scripts/ci/check-edge-native-closure.mjsfails ifrivetkit-napi/engine-cli/agent-os-corere-enter the adapter's production dependency tree.import(["@rivetkit","rivetkit-napi"].join("/"))that Deno can't statically resolve. If that's ever "simplified" to a literalimport("@rivetkit/rivetkit-napi"), Deno's eszip would statically snapshot it again — a regression neither the closure check norsize-limitcan see (the literal import stays external, changing nodependenciesfield and not inflating the bundle). The same script now also greps the builtdist/mod.mjsand fails on any literalimport()/require/fromof a forbidden package. The array-join sites innapi-runtime.ts/native.tscarryLOAD-BEARINGcomments so the obfuscation isn't cleaned up by mistake. (Added in response to the automated review.)size-limitondist/mod.mjs.Notes
vercel/firebase/cloudflare-workersadapters (not included here).rivetkitis untouched, so the Node/native/self-host path is unaffected.🤖 Generated with Claude Code