Skip to content

feat(cli): support devEngines for Node.js runtime and package manager selection#1760

Merged
fengmk2 merged 23 commits into
mainfrom
feat/dev-engines
Jun 8, 2026
Merged

feat(cli): support devEngines for Node.js runtime and package manager selection#1760
fengmk2 merged 23 commits into
mainfrom
feat/dev-engines

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jun 4, 2026

Copy link
Copy Markdown
Member

Implements rfcs/dev-engines.md (included in this PR), with a compatibility-first rule: existing .node-version and packageManager sources keep winning, devEngines becomes the default for new projects, and conflicts are surfaced by vp env doctor instead of silently resolved.

Changes

  • Detect devEngines.packageManager between the packageManager field and lockfiles; version ranges resolve against downloaded versions first, then the registry, and are never frozen into an exact pin
  • Auto-pin (lockfile detection, vp migrate) writes devEngines.packageManager instead of the packageManager field
  • devEngines.runtime now ranks above engines.node for Node.js version resolution
  • vp env pin / unpin target devEngines.runtime when no .node-version exists, with a --target override; an existing engines.node is never modified
  • vp env doctor gains a devEngines section with semver-aware conflict checks

Validation

just check, just test, crate-scoped cargo clippy --deny warnings, vp check, and pnpm test:unit all pass. Snap diffs reviewed: the packageManager to devEngines.packageManager swap plus deduplicated invalid-engines warnings.

Follow-ups

  • Templates: add devEngines.runtime alongside the kept engines.node
  • vp migrate: .nvmrc / Volta pins to devEngines.runtime with alias-to-semver conversion

Closes #864


Note

Medium Risk
Changes core Node/PM resolution order and mutates package.json on pin and auto-detect; behavior shifts for projects that relied on engines.node beating devEngines or on packageManager auto-writes.

Overview
Implements devEngines per rfcs/dev-engines.md with a compatibility-first rule: existing .node-version and top-level packageManager still win when present; new or inferred pins favor devEngines.

Node.js resolution now prefers devEngines.runtime over engines.node (after .node-version). vp env pin / unpin can write or remove pins in package.json#devEngines.runtime when there is no .node-version (or via --target), with optional sync prompts when .node-version diverges from a declared runtime range. engines.node is never modified by pin.

Package manager detection reads devEngines.packageManager after packageManager and before lockfiles, resolves semver ranges via cached installs then npm abbreviated metadata, and auto-pin from lockfile/default detection writes devEngines.packageManager (not packageManager). Conflicts between packageManager and devEngines warn today (future hard error).

vp env doctor adds a devEngines section (semver-aware runtime/PM/spec checks, monorepo workspace root for PM). Shared format-preserving package.json edits and a new UnsupportedDevEnginesPackageManager error support these flows.

Reviewed by Cursor Bugbot for commit 8ce926e. Configure here.

@fengmk2 fengmk2 self-assigned this Jun 4, 2026
@netlify

netlify Bot commented Jun 4, 2026

Copy link
Copy Markdown

Deploy Preview for viteplus-preview canceled.

Name Link
🔨 Latest commit 4808cfe
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a26b5d468d5e600086547c2

@fengmk2 fengmk2 force-pushed the feat/dev-engines branch from 94c0be0 to f67b97f Compare June 4, 2026 08:02
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

✅ Staging deployment successful!

Preview: https://viteplus-staging.void.app/
Commit: 4808cfe

@fengmk2

This comment was marked as outdated.

Comment thread crates/vite_install/src/package_manager.rs Outdated
@fengmk2 fengmk2 force-pushed the feat/dev-engines branch from c13a831 to bd6770e Compare June 5, 2026 07:08
@fengmk2 fengmk2 added test: e2e Auto run e2e tests test: create-e2e Run `vp create` e2e tests labels Jun 5, 2026
@fengmk2

This comment was marked as outdated.

Comment thread crates/vite_global_cli/src/commands/env/doctor.rs
Comment thread crates/vite_global_cli/src/commands/env/pin.rs
fengmk2 added 5 commits June 6, 2026 16:17
…ction

Implement rfcs/dev-engines.md with a compatibility-first rule: existing
.node-version and packageManager sources keep winning for writes, while
devEngines.runtime and devEngines.packageManager become the recommended
default for new projects. Conflicts are surfaced by vp env doctor
(semver-aware), never silently resolved.

- Parse devEngines per the OpenJS spec (single/array shapes, optional
  version, onFail with positional defaults, lenient on malformed entries)
- Detect devEngines.packageManager between the packageManager field and
  lockfiles; resolve version ranges (cached-first, then registry); never
  freeze a range into an exact pin
- Auto-pin lockfile-detected package managers into devEngines.packageManager
  instead of the packageManager field (vp migrate included)
- Move devEngines.runtime above engines.node in Node.js version resolution
- vp env pin/unpin write devEngines.runtime when no .node-version exists,
  with a --target override; existing engines.node is never modified
- vp env doctor gains a devEngines section with semver-aware conflict checks

Closes #864
Mirror the test matrix from npm/npm-install-checks test/check-dev-engines.js,
mapped to Vite+ semantics: npm validates the current environment and throws
on malformed input, while Vite+ provisions the environment and reads
devEngines leniently (rfcs/dev-engines.md), so npm's throw cases pin down our
skip/treat-as-default behavior for the same inputs.

- vite_shared: empty arrays, non-object devEngines/fields, non-string
  name/version/onFail values, extra entry properties, unrecognized sub-fields
- vite_install: empty-array fallthrough, all-unsupported array onFail
  handling, first-supported-entry selection; extract
  dev_engines_package_manager_conflict_message() for direct unit tests
- vite_js_runtime: runtime array form, no-node-entry and name-only
  fallthrough to engines.node
- vite_global_cli: extract collect_dev_engines_findings() and cover all
  doctor findings (conflicts, spec violations, notes, all-satisfied)
Auto-pin replaced the whole devEngines.packageManager value, dropping
alternate entries the spec allows (e.g. other package managers declared
with onFail: ignore) when detection fell through to a lockfile. Preserve
them instead: append to an existing array, convert an existing single
entry to array form, and only write a single entry when the field is
absent or malformed.

Also regenerate the create-flow snapshots (new-vite-monorepo,
new-vite-monorepo-bun, create-org-bundled) that were left stale after
setPackageManager() was retargeted to devEngines.packageManager, which
broke the CLI snap test and E2E jobs in CI.
- Guard against spreading a malformed non-object devEngines value in
  setPackageManager, which corrupted package.json with numeric index keys
- Make vp env doctor packageManager checks read the workspace root
  package.json (the file vp install actually uses) instead of the nearest
  one, fixing wrong or missing diagnostics in monorepos
- Fetch the npm abbreviated metadata document (KBs) instead of the full
  packument (multi-MB) when resolving devEngines version ranges
- Allow prerelease versions when a range explicitly requests them
  (e.g. ^12.0.0-0) and no stable version satisfies it
- Widen the snap normalizer regex to cover prerelease identifiers with
  hyphens and build metadata
- Extract shared confirm-overwrite and success-message helpers in vp env
  pin; pin --force with an identical version now no-ops as Already pinned
- Render uncached devEngines ranges without the v prefix in vp --version
- The doctor .node-version vs devEngines.runtime conflict check now follows
  the resolution walk on both sides: it fires only when a .node-version
  actually wins resolution, and finds the devEngines.runtime declaration in
  ancestor manifests too. This also removes a false positive where a parent
  .node-version was flagged against a nearer devEngines.runtime that wins
  resolution
- vp env pin (show) now reports inherited devEngines.runtime pins from
  parent directories, matching the existing .node-version inheritance
@fengmk2 fengmk2 force-pushed the feat/dev-engines branch from 937fc1f to e3f4ba0 Compare June 6, 2026 08:26
@fengmk2 fengmk2 changed the title feat: support devEngines for Node.js runtime and package manager selection feat(pm): support devEngines for Node.js runtime and package manager selection Jun 6, 2026
@fengmk2 fengmk2 changed the title feat(pm): support devEngines for Node.js runtime and package manager selection feat(cli): support devEngines for Node.js runtime and package manager selection Jun 6, 2026
@fengmk2

fengmk2 commented Jun 6, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit e3f4ba0. Configure here.

fengmk2 added 7 commits June 6, 2026 16:31
- Replace the planned 1-hour TTL range-resolution cache with the actual
  behavior: cached-satisfying-version short-circuits, registry consulted
  only while nothing satisfying is downloaded (abbreviated metadata)
- Document the prerelease rule: excluded unless the range itself contains
  a prerelease marker and no stable version satisfies it
- Document that auto-pin preserves existing devEngines.packageManager
  entries (append to array, convert single entry to array form)
- Document doctor scoping: runtime checks are resolution-aware and walk
  ancestor manifests; package-manager checks use the workspace root
- Document inherited devEngines.runtime pins in vp env pin output and
  the already-pinned no-op
Quality-only cleanup from /simplify, no behavior change:

- Add vite_shared::PackageJson::dev_engines_runtime() accessor and use it
  in the four readers (runtime.rs, config.rs, js_executor.rs, pin.rs,
  doctor.rs) that re-implemented the same dev_engines.runtime[node] chain
- Add vite_shared::dev_engine_entry() factory for the canonical
  {name, version, onFail: download} shape, used by pin and auto-pin
- Add PackageManagerType::from_name() and use it for the doctor
  supported-package-manager check instead of a parallel SUPPORTED const
- Remove the unused OnFail and PackageManagerSource Display impls
- Extract read_workspace_root_doc() to flatten doctor's nested match
- Collapse the duplicated unsupported-package-manager warn/note message
- Drop the node_version_exists param threaded into pin_dev_engines;
  emit the shadowing warning at the call site
find_cached_package_manager_version considered an install complete when only
the plain bin existed, while download_package_manager (and the bun path)
require the plain bin plus the .cmd and .ps1 shims. Range resolution could
therefore select a partially written cache entry that the download path would
re-do, which is most likely to bite on Windows where the .cmd/.ps1 wrappers
are the ones actually invoked.

Extract is_package_manager_install_complete() as the single source of truth
and use it in all three places. Add cross-platform tests covering a partial
install being skipped, a partial-only cache resolving to None, and the
completeness predicate itself.
The .cmd/.ps1 wrappers are only invoked on Windows, so checking them on
other platforms wastes two stat calls per cache entry (and per download
fast-path). Gate those two checks behind cfg(windows); the plain bin is
still required everywhere.

Because the check is shared, the cache and download fast-path still agree
on every platform, now with a platform-accurate notion of complete: off
Windows a bin-only install is usable, on Windows the wrappers are required.
Tests updated to assert the per-platform behavior.
Quality-only cleanup from /simplify, no behavior change:

- find_cached_package_manager_version: compare the in-memory version
  against the running best before stat'ing the install, so the filesystem
  check is skipped for versions that cannot win (saves stats on the shim
  hot path, more when read_dir yields the highest version early)
- Route both download fast-paths' post-lock re-checks through
  is_package_manager_install_complete instead of a bare plain-bin stat, so
  the function honors its own single-source-of-truth contract. Equivalent
  in practice: create_shim_files runs under the lock and writes all shims
  together, and off Windows the helper checks only the plain bin
- Drop the now-dead bin_file locals and inline install_dir.join("bin")
  at the create_shim_files call sites
onFail is parsed, preserved, and validated, but its full behavioral
matrix is not implemented in this PR. Correct the docs to say so:

- RFC 2.3: mark the runtime onFail matrix as not-yet-acted-on (managed
  mode always downloads); keep it as documented future behavior
- RFC 3.2: packageManager onFail is acted on only when no array entry
  names a supported package manager; a selected entry's onFail does not
  yet drive fallback on resolve/download failure
- Spec compliance matrix + Phase 3 plan: mark onFail as partial/deferred
- Add a Deferred / Future Work section laying out the per-entry
  packageManager fallback and the runtime onFail matrix
- package-manager-detection.md and docs/guide/install.md: same narrowing

No code change; onFail behavior is unchanged.
/simplify on the docs changes:
- env.md Project Setup: drop the parenthetical that duplicated the
  Manage-section vp env pin description
- install.md: drop the obscure array-of-all-unsupported onFail edge case
  (RFC-level detail); keep the user-facing 'only download is differentiated'
  caveat
@fengmk2

fengmk2 commented Jun 6, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@fengmk2

fengmk2 commented Jun 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 8ce926e. Configure here.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

fengmk2 added 2 commits June 6, 2026 22:29
resolve_latest_satisfying_version used version_req.contains('-') to decide
whether to allow prerelease versions when no stable version satisfies the
range. An npm hyphen range like "1.0.0 - 2.0.0" also contains '-', so it
would wrongly enable the prerelease fallback and could select a prerelease
the user never asked for.

Replace the substring check with requirement_requests_prerelease, which
splits on whitespace and only counts a hyphen embedded in a comparator
token (e.g. ^1.0.0-rc), not the lone ' - ' hyphen-range separator.
@fengmk2 fengmk2 marked this pull request as ready for review June 8, 2026 02:07
@fengmk2 fengmk2 requested review from TheAlexLichter and cpojer June 8, 2026 02:07
fengmk2 added 8 commits June 8, 2026 10:26
vp env doctor had no snap coverage (only unit tests on
collect_dev_engines_findings, which bypass the live command). doctor's
output is mostly environment-dependent, so this follows the
package-manager-diagnostics pattern: it sets up a project whose
.node-version conflicts with devEngines.runtime and whose packageManager
conflicts with devEngines.packageManager, runs vp env doctor, and asserts
the two conflict warnings render (via a node script, not a raw snapshot of
the volatile sections). Covers the render + resolution-gating path the
unit tests skip.
The previous step redirected doctor output to a file and only printed a
confirmation string, so the snapshot never captured the actual command
output and a wording/format change would be invisible in the snap diff.
Now the node script strips ANSI, extracts just the deterministic
devEngines section (the other doctor sections are environment-dependent),
and prints it, so snap.txt is a real golden file of the rendered findings.
…gines.runtime coexistence

Clarify in the RFC that compatible coexistence of the two Node-version
sources is intentionally not flagged (not even as a note): they serve
different tool ecosystems (.node-version for fnm/nvm/CI, devEngines.runtime
for npm/pnpm), so keeping both is a legitimate interop pattern. Doctor warns
only when they actually diverge, which also catches later drift.
…urce

The Source line preferred source_path (the package.json path) and dropped
the descriptor, so a version resolved from engines.node and one from
devEngines.runtime both rendered as <cwd>/package.json, indistinguishable.

Append the field name when the source is a package.json field, matching
vp env pin's output: 'package.json (devEngines.runtime)' vs
'package.json (engines.node)'. .node-version and pathless sources are
unchanged. Extracted format_version_source as a tested helper.
vp env --help renders a hand-written HelpDoc in help.rs, separate from
clap's derived help, so the cli.rs doc-comment updates only fixed
vp env pin --help. The env subcommand list still described pin as
'creates .node-version' and unpin as 'Remove the .node-version file',
which no longer matches the compatibility-first write target (.node-version
or devEngines.runtime). Update both summaries and regenerate the
cli-helper-message snapshot.
The test hardcoded Unix-absolute paths (/proj/package.json), which
AbsolutePathBuf::new rejects on Windows (no drive letter), panicking on
unwrap. Build the paths from a TempDir and assert against each path's own
display string so the test holds on every platform.
Comment thread crates/vite_global_cli/src/commands/env/pin.rs Outdated
The user runs 'vp env pin <version>' explicitly, so pressing Enter at the
overwrite confirmation should accept. Change the prompt to (Y/n) and cancel
only on an explicit no instead of requiring an explicit y.
@fengmk2 fengmk2 merged commit 5290951 into main Jun 8, 2026
93 checks passed
@fengmk2 fengmk2 deleted the feat/dev-engines branch June 8, 2026 13:01
@fengmk2 fengmk2 mentioned this pull request Jun 17, 2026
fengmk2 added a commit that referenced this pull request Jun 17, 2026
Release vite-plus v0.2.0.

Vite+ now consumes upstream Vitest directly (no wrapper), raises the
minimum supported Node.js version to 22.18.0, and ships corepack and
devEngines support.

### Highlights

- **`vp test` now runs upstream Vitest directly (breaking)**: Vite+ used
to ship `@voidzero-dev/vite-plus-test`, a rebundled copy of Vitest that
lagged upstream releases. That package is removed; `vp test` now runs
the real upstream `vitest`, which is installed automatically as a
dependency of `vite-plus` (you no longer add `vitest` or `@vitest/*`
yourself, and `vite` still resolves to `@voidzero-dev/vite-plus-core`
via package-manager overrides). Your `import ... from 'vite-plus/test'`
code keeps working unchanged and `vp migrate` updates existing projects
([#1588](#1588)), by
@Brooooooklyn
- **Minimum supported Node.js version raised to `^22.18.0 || >=24.11.0`
(breaking)**: Node 20 reached end-of-life and the bundled tsdown already
required `^22.18.0`, so the published engines range now matches what `vp
pack` can actually deliver; `vp exec` / `vp run` / `vp dlx` reject
projects resolving an older Node with the existing incompatibility error
([#1813](#1813)), by
@fengmk2
- **Corepack now works under Vite+**: `corepack` is a default `vp env
setup` shim, resolved managed-global, then Node-bundled (Node <= 24),
then auto-installed (Node 25+, which dropped corepack); `corepack
enable` / `disable` land their pnpm/yarn launchers on PATH and
Vite+-owned shims are restored if corepack replaces them
([#1808](#1808)), by
@fengmk2
- **devEngines support for runtime and package-manager selection**:
Vite+ reads `devEngines.runtime` (ranked above `engines.node`) and
`devEngines.packageManager`; auto-pin and `vp migrate` write
`devEngines.packageManager`, `vp env pin` / `unpin` target
`devEngines.runtime`, and `vp env doctor` reports conflicts instead of
silently resolving them
([#1760](#1760)), by
@fengmk2

### Features

- `vp pm approve-builds`: forward to npm's new `approve-scripts` /
`deny-scripts` (npm >= 11.16.0) instead of the previous no-op, matching
`pnpm approve-builds` / `bun pm trust`; mixed approve+deny is rejected
with actionable guidance and npm's advisory-only caveat is surfaced
([#1733](#1733)), by
@fengmk2
- `vp create`: support local monorepo templates declared in
`create.templates` in `vite.config.ts`; `vp create vite:generator`
scaffolds a Bingo generator and auto-registers it in the picker,
replacing the old package.json-keyword inference
([#1777](#1777)), by
@fengmk2
- `vp create`: detect direct dependencies whose build scripts the
package manager gated (e.g. native builds like `better-sqlite3`) and act
on them; prompt to approve each (default off) interactively, point at
`vp pm approve-builds` non-interactively, or build them with
`--approve-builds`
([#1828](#1828)), by
@fengmk2
- `vp config`: add `--no-hooks` and `--no-agent` opt-outs to skip
git-hook installation and coding-agent instruction updates
([#1842](#1842)), by
@leno23
- `vp list -g`: sort the global package list output so entries appear in
a stable order
([#1748](#1748)), by
@liangmiQwQ
- Upgrade upstream dependencies: rolldown `1.0.3 -> 1.1.1`, tsdown
`0.22.1 -> 0.22.3`, oxlint `1.67.0 -> 1.70.0`, oxfmt `0.52.0 -> 0.55.0`,
vitest `4.1.8 -> 4.1.9`, and the oxc toolchain `0.133.0 -> 0.136.0`
([#1749](#1749),
[#1767](#1767),
[#1812](#1812),
[#1834](#1834),
[#1855](#1855)), by
@voidzero-guard[bot]

### Fixes & Enhancements

- Security: resolve open Rust Dependabot advisories by bumping
transitive `openssl` `0.10.76 -> 0.10.80` (`openssl-sys` `0.9.112 ->
0.9.116`), fixing five high-severity rust-openssl issues (buffer
overflows in key derivation, AES key wrap, and digest finalization; an
unchecked PSK/cookie trampoline length leaking adjacent memory; and
OCSP-responder undefined behavior:
[GHSA-pqf5-4pqq-29f5](GHSA-pqf5-4pqq-29f5),
[GHSA-8c75-8mhr-p7r9](GHSA-8c75-8mhr-p7r9),
[GHSA-ghm9-cr32-g9qj](GHSA-ghm9-cr32-g9qj),
[GHSA-hppc-g8h3-xhp3](GHSA-hppc-g8h3-xhp3),
[GHSA-xp3w-r5p5-63rr](GHSA-xp3w-r5p5-63rr)),
and drop the unmaintained, unsound `libyml`
([GHSA-gfxp-f68g-8x78](GHSA-gfxp-f68g-8x78),
high) by removing dead `serde_yml` code
([#1742](#1742)), by
@fengmk2
- Security (docs site): update `mermaid` `11.13.0 -> 11.15.0` to fix
improper `classDef` sanitization in state diagrams that allowed HTML
injection
([CVE-2026-41149](https://nvd.nist.gov/vuln/detail/CVE-2026-41149) /
[GHSA-ghcm-xqfw-q4vr](GHSA-ghcm-xqfw-q4vr),
medium severity; `<script>` tags are stripped so it does not reach XSS)
([#1745](#1745)), by
@renovate[bot]
- `vp check --fix` / `vp staged`: create/migrate now wrap inline Vite
`plugins: [...]` arrays with `lazyPlugins(...)` so plugin factories
aren't eagerly executed (and don't hang on open handles) during
lint/format/check config loading
([#1752](#1752)), by
@jong-kyung
- `vp migrate`: complete pending migration work for projects that
already have `vite-plus` installed (scripts, imports, tsconfig types,
ESLint/Prettier, legacy hooks, package-manager settings) instead of
treating `vite-plus` as migration-complete; fully migrated projects stay
idempotent
([#1821](#1821)), by
@jong-kyung
- `vp create` / `vp migrate`: detect shorthand `fmt,` / `lint,` config
keys so a duplicate inline block is no longer injected
([#1843](#1843)), by
@fengmk2
- IDE oxlint/oxfmt wrappers: set `VP_COMMAND` so `lazyPlugins()` skips
framework plugins during LSP config reads, preventing a stray
`.svelte-kit` (and similar) directory at the monorepo root
([#1764](#1764)), by
@jong-kyung
- `vp lint` / `vp run -r lint` on Windows: keep the absolute `tsgolint`
path for workspace lint runs instead of downgrading it to a wrong
cwd-relative path
([#1758](#1758)), by
@semimikoh
- oxlint wrapper: set the `tsgolint` path so type-aware lint resolves it
([#1811](#1811)), by
@jong-kyung
- `vp install -g`: use a unique backup directory and treat stale-backup
cleanup as best-effort so a locked Windows binary no longer fails an
otherwise successful reinstall
([#1753](#1753)), by
@fengmk2
- `vp install -g`: remove stale managed binary shims when a reinstalled
package drops a bin from its `package.json#bin`
([#1765](#1765)), by
@liangmiQwQ
- `vp create --git`: surface git's actual stdout/stderr when the initial
commit fails instead of always blaming `user.name` / `user.email`
([#1819](#1819)), by
@fengmk2
- `vp create vite:generator`: reject `--git` / `--no-git`, since adding
a generator to an existing monorepo does not initialize git
([#1788](#1788)), by
@jong-kyung
- Global CLI: harden `find_system_tool` against a self-exec loop (skip
the running executable's own bin directory) and fix two
`vite_global_cli` tests that could hang
([#1820](#1820)), by
@fengmk2
- CLI help: unify alias display
([#1832](#1832)), show
supported `run` options
([#1797](#1797)), show
`--fail-if-no-match` in `exec` help
([#1798](#1798)), add the
`implode` documentation link
([#1796](#1796)), and
handle nested-command typo help
([#1803](#1803)), by
@jong-kyung

### Docs

- Document `vp create` opt-out options
([#1790](#1790)), by
@jong-kyung
- Document `vp upgrade` options
([#1847](#1847)), by
@jong-kyung
- Align the config overview with the sidebar
([#1846](#1846)), by
@jong-kyung
- Sync the documented command lists with the help output
([#1850](#1850)), by
@jong-kyung
- Clarify lazy plugin side effects
([#1841](#1841)), by
@leno23
- Add JongKyung's X profile
([#1844](#1844)) and
update Christoph's X profile
([#1845](#1845)) on the
team page, by @jong-kyung

### Refactor

- Remove the CLI tips system; the shortcuts it printed on `vp install`
are already covered by the help system and added unnecessary complexity
([#1799](#1799)), by
@cpojer

### Chore

- Re-enable Renovate dependency updates with a targeted ignore-list
([#1744](#1744)), by
@fengmk2
- Keep generated NAPI bindings during upgrade-deps
([#1759](#1759)), by
@fengmk2
- Remove the `vite_glob` dependency from vite-plus
([#1763](#1763)), by
@wan9chi
- Keep `sync-remote` from churning `pnpm-workspace.yaml` (dedupe
`minimumReleaseAgeExclude`, preserve comments)
([#1787](#1787)), by
@fengmk2
- Make unix `just test` runnable
([#1755](#1755)), by
@situ2001
- CI: reuse `just lint` and `just test` as the single source of truth
([#1809](#1809)), pin
`cargo-zigbuild` to a git rev to fix the aarch64-musl link failure
([#1815](#1815)), and keep
upgrade-deps green when rolldown bumps oxc
([#1833](#1833)), by
@fengmk2
- Update Rust to nightly-2026-06-10
([#1725](#1725)), typos to
v1.47.1 / v1.47.2
([#1772](#1772),
[#1775](#1775)), GitHub
Actions ([#1778](#1778),
[#1829](#1829)), and npm
packages ([#1779](#1779)),
by @renovate[bot]
- Bump `oxc-project/setup-node` to v1.3.1
([#1792](#1792)), by
@Boshen
- Refresh trusted stack stats on the docs homepage
([#1786](#1786),
[#1837](#1837)), by
@voidzero-guard[bot]

### Bundled Versions

| Tool | Version | Source |
| --- | --- | --- |
| vite | `8.0.16` |
[`f94df87`](vitejs/vite@f94df87)
|
| rolldown | `1.1.1` |
[`d7f919c`](rolldown/rolldown@d7f919c)
|
| tsdown | `0.22.3` | [npm](https://npmx.dev/package/tsdown/v/0.22.3) |
| vitest | `4.1.9` | [npm](https://npmx.dev/package/vitest/v/4.1.9) |
| oxlint | `1.70.0` | [npm](https://npmx.dev/package/oxlint/v/1.70.0) |
| oxlint-tsgolint | `0.23.0` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/0.23.0) |
| oxfmt | `0.55.0` | [npm](https://npmx.dev/package/oxfmt/v/0.55.0) |

### Upgrading from 0.1.24 to 0.2.0

This release has two breaking changes. For most projects the upgrade is
`vp upgrade`, bump the project's `vite-plus`, then `vp migrate`.

#### 1. Update the CLI

```bash
vp upgrade
```

#### 2. Node.js 20 is no longer supported

The minimum supported Node.js version is now `^22.18.0 || >=24.11.0`
(Node 20 reached end-of-life). If you are still on Node 20:

- Check your version: `node --version` (or `vp env doctor`)
- Move to a supported release: `vp env pin 22.18.0` (or a newer LTS), or
update your `.node-version` / `devEngines.runtime`

`vp exec` / `vp run` / `vp dlx` now refuse to run against a project that
resolves Node < 22.18.0.

#### 3. Vitest is now upstream (the wrapper is gone)

`@voidzero-dev/vite-plus-test` has been removed; Vite+ consumes upstream
`vitest` directly. Bump `vite-plus` first, then migrate:

```bash
vp update vite-plus --latest    # project's vite-plus -> 0.2.0 (ignores the old range, updates the lockfile); monorepo: add -r
vp migrate                      # local vite-plus is now 0.2.0, so the new migration runs
```

`vp update --latest` re-resolves `vite-plus` to the newest release
regardless of the old semver range, so the lockfile cannot pin you back
to 0.1.24. The project's local `vite-plus` is then 0.2.0, and since the
global `vp` delegates `migrate` to the project's local install, `vp
migrate` runs the new migration.

- Your `import { vi, ... } from 'vite-plus/test'` code is unchanged. `vp
migrate` rewrites any leftover `vitest` / `@vitest/*` imports and
normalizes stale `vitest: npm:@voidzero-dev/vite-plus-test@*` aliases.
- You no longer add `vitest` or `@vitest/*` yourself; they arrive
transitively through `vite-plus`.

### New Contributors

Welcome to our new contributor @situ2001! 🎉

**Full Changelog**:
v0.1.24...v0.2.0

---

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test: create-e2e Run `vp create` e2e tests test: e2e Auto run e2e tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support devEngines field

2 participants