Skip to content

feat: on-demand dependency manifest and deps option - #4839

Merged
pi0 merged 6 commits into
mainfrom
feat/on-demand-versions
Oct 18, 2026
Merged

pi0 merged 6 commits into
mainfrom
feat/on-demand-versions

Conversation

@pi0x

@pi0x pi0x commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Optional dependencies installed on demand were configured at each call site: ranges were duplicated (rollup ^4 and vite ^8 twice, azure ^4 hard-coded in error messages), some had no range at all, and build.config.ts kept its own hand-written lists.

This moves them into one manifest, deps.json at the repo root (typed and exported by src/utils/_deps.ts). Each entry has its supported version range, reason and install defaults (dev, autoInstall, projectOnly), plus runtime and types flags.

  • ensureDep / importDep / missingDepError apply the manifest defaults, so call sites are just importDep({ id, dir }). importDep also infers the module type from the id (DepModules in the manifest), so call sites no longer pass <typeof import("…")>. A call can still override reason (unenv and the kv/database config do).
  • build.config.ts builds optionalDeps (externals) and optionalTypeDeps from the manifest, and shimmedDeps from the files in src/shims/.
  • runtime-deps.ts builds its list of runtime deps from the manifest (runtime: true).
  • Packages that had no range now have one: @vercel/queue ^0.8.0 and zephyr-agent ^1.6.0 (taken from the versions we test with).

New deps option

Frameworks built on Nitro (e.g. Nuxt) can pass their own copies of on-demand dependencies by package name, generalizing vite.path:

createNitro({
  deps: {
    paths: {
      vite: import.meta.resolve("vite"),
      unstorage: import.meta.resolve("unstorage"),
      ocache: import.meta.resolve("ocache"),
    },
  },
});
  • Values are a path or file:// URL to the package directory or entry (same format as vite.path). The resolver behind vite.path moved to src/utils/_dep-path.ts, so it now works for any package and its subpaths.
  • ensureDep / importDep / resolveDep take paths (call sites pass nitro.options.deps?.paths). A package with an explicit path is never installed. Its version is still checked against the manifest range, and a path that isn't the package throws.
  • The runtime deps (unstorage, db0, ocache, unenv) are bundled from the explicit path. rolldown uses deps.paths.rolldown, then falls back to resolving through deps.paths.vite.
  • Explicit vite and rolldown paths go through the same version check. The oxc loader (src/utils/oxc.ts) uses the explicit rolldown/vite too.
  • Packages without exports (e.g. xml2js) are resolved from their own directory (main, subpaths), and a path never falls back to another copy found next to it.
  • vite.path and deps.paths.vite are aliases (synced in the new resolveDepsOptions resolver). If both are set to different values, deps.paths.vite wins with a warning.
  • deps is a namespace, so related options (e.g. a resolve root or install mode) can be added next to paths later.
  • Not covered: the c12 shims (they load before the config exists), the third-party driver/connector libraries, and @azure/functions / @vercel/queue (the app bundle imports these by name from the project).

Shims (dotenv, giget, jiti) are not on-demand deps of Nitro itself, because their range is set by the bundled library (c12). Their ranges live in a separate shims section of deps.json, next to the library they belong to: dotenv ^16 || ^17 || ^18 and giget ^3.1.0 are new.

Syncing ranges (pnpm sync-deps)

scripts/sync-deps.ts updates a deps.json range only once the tested devDependencies version falls outside it (for example, a Renovate major bump). It keeps the range's precision (^8 → ^9, ^0.8.0 → ^0.9.2) and adds a new major to || ranges (^16 || ^17 || ^18 → … || ^19). It refuses a shim range that c12's peer range doesn't accept, and a tested version lower than the range. It also runs from scripts/update-deps.ts, and the manifest unit test's failure message points to it.

Tests: test/unit/deps.test.ts checks that:

  • every manifest range covers the devDependencies version we test with
  • runtime deps are installed as dependencies without prompting
  • every shim's range is within c12's peer range and covers the tested version
  • importDep infers module types and vite.path / deps.paths.vite stay in sync

dep.test.ts covers resolving from explicit paths (directory, entry, file://, subpaths), the version check and a wrong path. build-runtime-deps.test.ts builds with deps.paths.ocache pointing to a marked copy and checks that the bundle uses it.

Build output change: @azure/functions used to be bundled into dist/runtime/_chunks/libs/@azure/functions.mjs (~77 kB), even though the azure preset requires it in the project and adds it to traceDeps. It is now external, like the other manifest entries. Apart from import order, it's the only change in dist; the .d.mts files are identical.

Not included yet: the update check (recommending or prompting for upgrades). The manifest is where a minimum-recommended version would go.

To review: the new ranges for @vercel/queue (^0.8.0), zephyr-agent (^1.6.0), giget (^3.1.0) and dotenv (^16 || ^17 || ^18). Users with an installed version outside them will now see a "please update" warning, and on-demand installs of @vercel/queue now pin ^0.8.0. Also, db0 required by the unstorage db0 driver now installs without prompting (manifest default), like db0 for nitro/database.

🤖 Generated with AI assistant

Supported ranges, reasons and install defaults of optional dependencies now
live in `src/utils/_deps.ts`. Shims declare their own range within the one of
the bundled library.
@vercel

vercel Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
nitro.build Ready Ready Preview Oct 18, 2026 1:50pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3a6b0b4d-64a4-4fee-9f61-940898d14113
📥 Commits

Reviewing files that changed from the base of the PR and between 6fe4056 and c5ab8b7.

📒 Files selected for processing: 44
  • AGENTS.md
  • build.config.ts
  • deps.json
  • docs/3.config/0.index.md
  • package.json
  • scripts/sync-deps.ts
  • scripts/update-deps.ts
  • src/build/plugins.ts
  • src/build/plugins/import-attributes.ts
  • src/build/plugins/oxc.ts
  • src/build/plugins/route-meta.ts
  • src/build/plugins/runtime-deps.ts
  • src/build/plugins/unenv.ts
  • src/build/rolldown/_import.ts
  • src/build/rolldown/build.ts
  • src/build/rollup/_import.ts
  • src/build/unbundled/plugins.ts
  • src/build/vite/_import.ts
  • src/config/loader.ts
  • src/config/resolvers/builder.ts
  • src/config/resolvers/cache.ts
  • src/config/resolvers/deps.ts
  • src/dev/runner-deps.ts
  • src/prerender/prerender.ts
  • src/presets/azure/_functions.ts
  • src/presets/iis/utils.ts
  • src/presets/vercel/preset.ts
  • src/presets/zephyr/preset.ts
  • src/shims/README.md
  • src/shims/dotenv.ts
  • src/shims/giget.ts
  • src/shims/jiti.ts
  • src/types/config.ts
  • src/utils/_dep-path.ts
  • src/utils/_deps.ts
  • src/utils/database.ts
  • src/utils/dep.ts
  • src/utils/oxc.ts
  • src/utils/storage.ts
  • test/unit/build-runtime-deps.test.ts
  • test/unit/build-unenv.test.ts
  • test/unit/dep.test.ts
  • test/unit/deps.test.ts
  • test/unit/zephyr-preset.test.ts
+------------------------------------------------+
| Squeezing intelligence out of LLMs since 2023. |
+------------------------------------------------+
  \
   \     /)/)
        ( '')
        /  |
      o(___)
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4839

commit: c5ab8b7

Frameworks built on Nitro can pass their own copies of on-demand dependencies
(e.g. `unstorage`, `db0`, `ocache`), generalizing `vite.path` (now an alias of
`deps.vite`).
@pi0x pi0x changed the title refactor: centralize on-demand dependency versions in a manifest feat: on-demand dependency manifest and deps option Oct 18, 2026
- check the version of explicit `vite` and `rolldown` paths
- resolve packages without `exports` from their explicit path only
- do not pass `paths` for deps the bundle imports by name (azure, vercel)
- honour `deps.paths` when loading oxc from `rolldown`
- ignore `undefined` options when applying manifest defaults
- warn when `vite.path` and `deps.paths.vite` differ
`pnpm sync-deps` updates the supported ranges (including shims) once the tested
`devDependencies` versions are out of them, and runs as part of `scripts/update-deps.ts`.
@pi0
pi0 marked this pull request as ready for review October 18, 2026 13:56
@pi0
pi0 merged commit 7730326 into main Oct 18, 2026
14 of 15 checks passed
@pi0
pi0 deleted the feat/on-demand-versions branch October 18, 2026 13:57

This branch was successfully deployed

1 active deployment
Preview — c5ab8b7e Deployed Oct 18, 2026 by vercel[bot]
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.

2 participants