Skip to content

[eas-cli] Add deno package manager support for builds#3951

Open
yyq1025 wants to merge 1 commit into
expo:mainfrom
yyq1025:feat/deno-package-manager
Open

[eas-cli] Add deno package manager support for builds#3951
yyq1025 wants to merge 1 commit into
expo:mainfrom
yyq1025:feat/deno-package-manager

Conversation

@yyq1025

@yyq1025 yyq1025 commented Jul 3, 2026

Copy link
Copy Markdown

Why

Deno 2 works well as a package manager for Expo/React Native projects: deno install materializes a Node-compatible node_modules tree that Metro, expo export, autolinking, and pod install all resolve correctly (verified end-to-end on an Expo SDK 56 / RN 0.85 app with native modules). But EAS Build only detects npm / yarn / pnpm / bun lockfiles, so a deno-managed project (which has only deno.lock) silently falls back to a yarn install with no lockfile — an unpinned dependency tree, the exact drift a lockfile is meant to prevent.

This mirrors how bun support was added (see #2782 for the bun.lock precedent). The immediate audience is eas build --local, where deno is already on the user's machine.

Running the Expo CLI itself under the deno runtime is also a supported path upstream: the Deno team tracked Expo compatibility in denoland/deno#22970 and closed it after fixing the blockers.

How

Following the existing bun pattern across the build pipeline, with three deno-specific semantic mappings:

  • Detection (build-tools/utils/packageManager.ts): a project (or its workspace root) with deno.lock resolves to PackageManager.DENO. @expo/package-manager has no deno support yet, so the check lives here for now — and it only runs when the external resolver finds no Node package manager lockfile, so any existing npm/yarn/pnpm/bun project is completely unaffected. Happy to follow up with a PR to @expo/package-manager to move detection to its proper layer.
  • Install (common/installDependencies.ts): deno install, with --frozen when a frozen lockfile is requested (deno's equivalent of --frozen-lockfile). deno install has no --verbose flag, so EAS_VERBOSE is not forwarded.
  • Expo CLI (utils/project.ts, steps/functions/prebuild.ts): deno run -A npm:expo <args> — deno has no bare deno expo bin runner; npm:expo resolves the copy from local node_modules when present.
  • Lifecycle hooks (utils/hooks.ts): deno task <hook>deno task is deno's equivalent of <packageManager> run for package.json scripts (deno run executes files, not scripts).
  • deno.lock is accepted by ensureLockfileExistsAsync, and 'deno' is a valid requiredPackageManager metadata value and EAS_FALLBACK_PACKAGE_MANAGER value.

Scope note: cloud workers don't have deno installed yet, so this primarily targets eas build --local. On cloud, a deno-only project changes from "silent unpinned yarn install" to an explicit spawn failure — arguably more honest, but I'm happy to gate detection to local builds or add worker provisioning (mirroring installBun()) if you'd prefer either.

One known follow-up for full parity: deno blocks npm lifecycle scripts by default (--allow-scripts); projects relying on postinstall-heavy native deps need a story for that. Left out of this PR to keep it reviewable — flagging for discussion.

Test Plan

New unit tests mirroring the bun coverage, all passing (yarn test in build-tools, eas-cli, eas-build-job; full lerna run build passes):

  • detection: deno.lock only → deno; deno.lock + yarn.lock → yarn (Node lockfile precedence); monorepo with deno.lock at workspace root → deno; EAS_FALLBACK_PACKAGE_MANAGER=deno
  • install args: deno install / deno install --frozen; EAS_VERBOSE not forwarded to deno
  • expo CLI: spawns deno run -A npm:expo doctor
  • hooks: spawns deno task eas-build-post-install
  • lockfile validation accepts deno.lock

Manual verification of the underlying assumption (deno-installed trees build correctly): on a deno-managed Expo SDK 56 / RN 0.85 monorepo app, deno install + expo export --platform ios (Hermes + DOM component bundles), expo-modules-autolinking resolve (38/38 module parity with the pnpm tree), expo prebuild, and pod install all succeed.

🤖 Generated with Claude Code

Detect deno as the package manager when a project (or its workspace
root) has a deno.lock lockfile and no Node package manager lockfile.
During builds, install dependencies with `deno install` (`--frozen`
when a frozen lockfile is requested), run the Expo CLI through
`deno run -A npm:expo`, and execute EAS build lifecycle hooks with
`deno task`, deno's equivalent of `<packageManager> run`.

deno.lock is also accepted by the lockfile presence check, and 'deno'
is a valid requiredPackageManager metadata value and
EAS_FALLBACK_PACKAGE_MANAGER value.

Detection lives in build-tools for now because @expo/package-manager
has no deno support; a Node lockfile always wins over deno.lock, so
existing projects are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yyq1025 yyq1025 force-pushed the feat/deno-package-manager branch from fd7f6a3 to 5e4f143 Compare July 3, 2026 22:36
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

Subscribed to pull request

File Patterns Mentions
**/* @douglowder
packages/eas-cli/src/build/** @sjchmiela

Generated by CodeMention

Warning: The preamble and epilogue options in commentConfiguration are deprecated. Use template instead.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant