Skip to content

research: respect full package.json (ranges + tree) under Bun zero-install (default auto-install) #690

Description

@vivek7405

Terminology correction (2026-06-24): this issue says "--no-install" in places, but that is the WRONG term. webjs's zero-install is default bun run dev with auto-install ON (no flag). The --no-install FLAG is the opposite (it DISABLES auto-install, for CI/prod strictness) and webjs does not use it. Read every "--no-install" below as "default auto-install / bun run dev zero-install". The research question is whether DEFAULT auto-install honors package.json ranges + the lockfile on a current (1.3.14) Bun.

Question

Make Bun zero-install (default bun run dev auto-install, no node_modules) resolve dependencies EXACTLY as npm install / bun install + node_modules would, for the FULL package.json: caret/tilde/x ranges, dist-tags, prerelease, peer + optional deps, npm: aliases, and the whole transitive tree, not just exact direct pins.

Background (verified in #684 + shipped in #685)

Goal

A zero-install Bun app (no node_modules) runs the SAME version set that npm install / bun install + node_modules would, across the whole tree, verified differentially.

Avenues to investigate

  1. bun install --lockfile-only (most promising): can Bun produce/refresh a bun.lock by RESOLUTION ONLY, with no node_modules? If yes, run it at scaffold/first-run (cheap), then feat: pin Bun zero-install deps via an onLoad specifier-rewrite from package.json #685's exact-pin reads the lock and pins every declared dep. The lock IS npm-equivalent resolution output, so this closes the range gap with zero node_modules.
  2. Transitive correctness: when auto-install fetches an exact dep (zod@3.22.4), does it resolve zod's OWN deps deterministically (per the lock / zod's manifest) or fetch them at latest? feat: pin Bun zero-install deps via an onLoad specifier-rewrite from package.json #685 only pins the app's DIRECT imports (the onLoad skips node_modules/cache dep files). Verify whether a bun.lock under zero-install pins the FULL tree.
  3. bun.lock + the feat: pin Bun zero-install deps via an onLoad specifier-rewrite from package.json #685 rewrite end-to-end: does a present bun.lock + the exact-pin rewrite ALREADY achieve full npm-equivalence today? Test differentially against a node_modules install of the same package.json.
  4. Boot-time resolve-once-and-cache: on first run with no lock, do a one-time resolution (lockfile-only or a registry query) writing a bun.lock / internal manifest, then pin from it. Trigger in the webjs-bun.mjs bootstrap or a webjs CLI step.
  5. Custom resolver (heavy fallback): re-implement semver max-satisfying + registry version queries to resolve ranges ourselves. Re-implements a package-manager solver; last resort.

Edge cases the solution must cover

caret/tilde/x/*/||/hyphen ranges, dist-tags (latest/next), prerelease versions, peer + optional deps, dedup, npm: aliases, git/file/workspace specifiers (bare today), and the full transitive tree.

Acceptance

A no-node_modules Bun app resolves to the identical version tree a node_modules install would (differential test). Then --no-install-by-default (scaffold + #682) becomes safe.

Cross-references

#684 (prior research, concluded exact-only via the onLoad rewrite), #685 (shipped exact-only pin), #682 (closed; the --no-install default this unblocks), #675 (zero-install bootstrap), #687.

Forward-looking research task; the first investigation pass (the bun install --lockfile-only avenue) is being recorded as comments below.

Metadata

Metadata

Assignees

Labels

researchResearch/design/decision record (no code); filter these to read design history

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions