feat(unstable): add --bundle flag to `deno compile` (#34527)
First cut at making `deno compile` ship a bundled entrypoint instead of embedding the entire `node_modules/` tree verbatim. Motivated by a real-world report comparing `deno compile` against `bun build --compile` on a 2700-module CLI, where Deno's binary was ~3x bigger almost entirely because of the raw npm payload. The flag is gated behind a "this is experimental" warning since several real cases aren't handled yet. When `--bundle` is set, the entrypoint is run through the existing esbuild-based bundler (ESM, platform=Deno, packages=Bundle, tree-shaking on) and the bundle is written to a temp `.mjs` next to the source. The standalone binary writer then sees a single self-contained file in the graph, so the existing managed-npm path naturally skips the VFS fill (no `Module::Npm` entries left after tree-shaking). The BYONM path, which fills the VFS unconditionally, is gated on the new flag. The existing `replace_require_shim` rewrite is reused so esbuild's "Dynamic require not supported" stub becomes a real `createRequire(import.meta.url)` call against `node:module`, so dynamic `require()` of `node:` builtins keeps working in denort. Known limitations for this PR (intentional, to keep it reviewable): native `.node` addons, worker entrypoints, and any module that does dynamic `require(path.join(__dirname, ...))` aren't traced and will break. CJS npm packages are also currently externalized by esbuild as a runtime `require()` against `node_modules`, which `--bundle` strips, so those break too; this is locked in by an expected-failure spec (`compile/bundle/npm_cjs_unsupported`) that should be removed once CJS packages are inlined into the bundle. The warning calls out the experimental status.
B
Bartek Iwańczuk committed
4ec12da8796b2d54d8428f9e2042c3e9f0532667
Parent: 3393603
Committed by GitHub <noreply@github.com>
on 5/31/2026, 8:07:38 AM