Skip to content

research: can webjs db/test/typecheck run under bun zero-install? #719

Description

@vivek7405

Question

Can webjs db / test / typecheck run under bun zero-install (no node_modules), and how? This is the deep research for #704 after its first approach (a runner that imports the tool bin + a spawn pin preload) was found broken.

Verdict

The spawned dev tools (drizzle-kit, the bun test runner, tsc) fundamentally need a materialized node_modules; bun's auto-install + global cache + plugins cannot substitute. The reconciling fix is to auto-materialize node_modules via a fast bun install (cheap because the deps are already in bun's global cache) and run the tool from the app context (the existing resolveBin path), NOT the runner / preload / bun x approach. The server (dev / start) stays true zero-install via the pin shim; only the spawned tooling materializes.

Findings (verified empirically on bun 1.3.14)

  1. bun x <tool> runs the tool from an ISOLATED temp dir (/tmp/bunx-.../node_modules/<tool>/), so drizzle-kit cannot resolve the APP's drizzle-orm. This fails EVEN WITH a full bun install present, so bun x was always the wrong tool, independent of zero-install. drizzle-kit must run from the app's own node_modules context.

  2. The db failure is a version mismatch surfaced by auto-install. drizzle-kit@1.0.0-rc.3 requires drizzle-orm/_relations, which exists in drizzle-orm@1.0.0-rc.3 but NOT in drizzle-orm@0.45.2. npm latest is 0.45.2 (the rc line is a prerelease under a non-latest tag), so bun's bare auto-install resolves drizzle-orm to 0.45.2 and the subpath is missing.

  3. Bun plugins (Bun.plugin onLoad / onResolve) do NOT intercept CommonJS require() resolution, only ESM imports. drizzle-kit's bin.cjs is CommonJS, so the pin shim cannot reach its internal require('drizzle-orm/_relations'). A bunfig preload DOES run under bun x (verified), but its onResolve never fires for the CJS require. onLoad on a cached CJS file also breaks it (returning { contents, loader } forces ESM parsing of a CJS module).

  4. package.json overrides and bunfig [install.overrides] do NOT reach the bun x temp process, so they cannot pin the version there.

  5. The fix works end to end. With the deps already in bun's global cache (zero-install DOES download to the global cache on disk), bun install materializes node_modules in ~57ms (measured). Running drizzle-kit from the app context then fully generates a real migration ([✓] Your SQL migration -> drizzle/<ts>_init/migration.sql). bun test (which has no auto-install at all) and tsc also work once node_modules exists.

Recommendation for #704 (separate implementation issue)

Drop the runner + the keystone-preload-for-tooling + the bin-import wiring (it cannot work). Instead: webjs db / test / typecheck under bun zero-install auto-materialize node_modules via a fast bun install, then run the existing resolveBin path. This is "no MANUAL install" (webjs does it transparently and fast), the honest reconciliation of the zero-install goal with the reality that CommonJS + esbuild tools and bun test need node_modules.

Tradeoff to document: after the first tool invocation node_modules exists, so the app is "installed" thereafter (everything keeps working; the user never typed an install command). The seamless progression is: start zero-install (instant dev), and the first time you need tooling, webjs materializes in tens of milliseconds.

Relates to #704, #684/#698 (the pin shim, which stays for the server), #669 (the zero-install vision), #718 (lockfile reproducibility, which the materialized lock would also serve).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions