Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,32 +147,19 @@ jobs:
- name: Pack packages into tgz
run: |
mkdir -p tmp/tgz
# Every tgz consumer below references fixed `*-0.0.0.tgz` filenames.
# A release commit can leave `packages/{core,cli}` at a published
# version (e.g. 0.1.22), which would make `pnpm pack` emit
# `*-0.1.22.tgz` instead. Pin both to 0.0.0 so the names stay stable.
# patch-project.ts serves these tgz through a local npm registry
# (packages/tools/src/local-npm-registry.ts), so `vp migrate` pins
# and installs them like a real release, with every package manager
# (including bun) resolving the standard
# `vite -> npm:@voidzero-dev/vite-plus-core@<version>` alias. Pin
# both packages to 0.0.0 so a correctly installed local build is
# always distinguishable from any published version
# (verify-install.ts asserts it), even on a release commit that
# leaves packages/{core,cli} at a published version.
(cd packages/core && npm pkg set version=0.0.0)
(cd packages/cli && npm pkg set version=0.0.0)
cd packages/core && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
cd packages/cli && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
# Bun is uniquely strict about peer-dep resolution:
# 1. It checks the *resolved target's* package name and version
# against the peer range (vitest 4.1.9 declares peer
# `vite ^6 || ^7 || ^8`).
# 2. A file: override pointing at the vite-plus-core tgz fails
# both the name check (target is `@voidzero-dev/vite-plus-core`,
# not `vite`) and the version check (0.0.0 is outside `^6|^7|^8`).
# pnpm/npm/yarn don't enforce either, and using the same core tgz as
# the file: target for both `vite` and `@voidzero-dev/vite-plus-core`
# is the only configuration they install cleanly. See
# https://github.com/oven-sh/bun/issues/8406.
#
# Generate a sibling vite-7.99.0.tgz: a copy of the core tgz with
# `package.json#name` rewritten to "vite" and `version` to 7.99.0.
# ecosystem-ci/patch-project.ts points its vite override at this
# tgz only for bun-based projects (e.g. bun-vite-template); pnpm-,
# npm- and yarn-based ecosystem projects use the real core tgz.
pnpm exec tool repack-vite-tgz tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz tmp/tgz/vite-7.99.0.tgz vite 7.99.0
# Copy vp binary for e2e-test job (findVpBinary expects it in target/)
cp target/${{ matrix.target }}/release/vp tmp/tgz/vp 2>/dev/null || cp target/${{ matrix.target }}/release/vp.exe tmp/tgz/vp.exe 2>/dev/null || true
cp target/${{ matrix.target }}/release/vp-shim.exe tmp/tgz/vp-shim.exe 2>/dev/null || true
Expand Down Expand Up @@ -476,13 +463,14 @@ jobs:
- name: Migrate in ${{ matrix.project.name }}
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
shell: bash
# patch-project.ts runs `vp migrate` and the follow-up `vp install`,
# handling pnpm's minimumReleaseAge gate per project (disabled so
# freshly published deps install, kept off for dify's time-based
# resolution policy). See its comments for the details.
# patch-project.ts starts a local npm registry serving the packed
# local build (it stays up for the later steps; the registry env is
# exported via GITHUB_ENV), then runs `vp migrate` and the follow-up
# `vp install` through it, with pnpm's minimumReleaseAge gate disabled
# so freshly published upstream deps install. See its comments.
run: node $GITHUB_WORKSPACE/ecosystem-ci/patch-project.ts ${{ matrix.project.name }}

- name: Verify local tgz packages installed
- name: Verify local packages installed
working-directory: ${{ runner.temp }}/vite-plus-ecosystem-ci/${{ matrix.project.name }}${{ matrix.project.directory && format('/{0}', matrix.project.directory) || '' }}
shell: bash
run: node $GITHUB_WORKSPACE/ecosystem-ci/verify-install.ts
Expand Down
97 changes: 54 additions & 43 deletions .github/workflows/test-vp-create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,34 +95,19 @@ jobs:
- name: Pack packages into tgz
run: |
mkdir -p tmp/tgz
# Every tgz consumer below references fixed `*-0.0.0.tgz` filenames.
# A release commit can leave `packages/{core,cli}` at a published
# version (e.g. 0.1.22), which would make `pnpm pack` emit
# `*-0.1.22.tgz` instead. Pin both to 0.0.0 so the names stay stable.
# The test jobs serve these tgz through a local npm registry
# (packages/tools/src/local-npm-registry.ts), so `vp create` pins
# and installs them like a real release, with every package manager
# (including bun) resolving the standard
# `vite -> npm:@voidzero-dev/vite-plus-core@<version>` alias. Pin
# both packages to 0.0.0 so a correctly installed local build is
# always distinguishable from any published version, even on a
# release commit that leaves packages/{core,cli} at a published
# version.
(cd packages/core && npm pkg set version=0.0.0)
(cd packages/cli && npm pkg set version=0.0.0)
cd packages/core && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
cd packages/cli && pnpm pack --pack-destination ../../tmp/tgz && cd ../..
# Bun is uniquely strict about peer-dep resolution:
# 1. It checks the *resolved target's* package name and version
# against the peer range (vitest 4.1.9 declares peer
# `vite ^6 || ^7 || ^8`).
# 2. A file: override pointing at the vite-plus-core tgz fails
# both the name check (target is `@voidzero-dev/vite-plus-core`,
# not `vite`) and the version check (0.0.0 is outside `^6|^7|^8`).
# pnpm/npm/yarn don't enforce either, and using the same core tgz as
# the file: target for both `vite` and `@voidzero-dev/vite-plus-core`
# is the only configuration they install cleanly. See
# https://github.com/oven-sh/bun/issues/8406.
#
# Generate a sibling vite-7.99.0.tgz: a copy of the core tgz with
# `package.json#name` rewritten to "vite" and `version` to 7.99.0.
# Only the bun matrix entry below points its vite override at this
# alias tgz; pnpm/npm/yarn keep pointing at the real core tgz so
# pnpm's workspace resolver doesn't trip on a "vite@<version>"
# registry lookup (the renamed tgz makes pnpm register the dep as
# vite@7.99.0 and then probe npmjs.org to validate the version).
pnpm exec tool repack-vite-tgz tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz tmp/tgz/vite-7.99.0.tgz vite 7.99.0
# Copy vp binary for test jobs
cp target/x86_64-unknown-linux-gnu/release/vp tmp/tgz/vp
ls -la tmp/tgz
Expand Down Expand Up @@ -179,15 +164,12 @@ jobs:
- yarn
- bun
env:
# Bun's strict peer check requires the `vite` override target's tgz to be
# named "vite" with a version satisfying vitest's `peer vite ^6 || ^7 || ^8`.
# The bun matrix entry uses the masquerade tgz (vite-7.99.0.tgz). pnpm/npm/yarn
# point at the real core tgz — anything else trips a registry lookup for
# vite@<version> when sub-package and override targets are both file: tgz aliases.
VITE_OVERRIDE_TGZ: ${{ matrix.package-manager == 'bun' && 'vite-7.99.0.tgz' || 'voidzero-dev-vite-plus-core-0.0.0.tgz' }}
VP_VERSION: 'file:${{ github.workspace }}/tmp/tgz/vite-plus-0.0.0.tgz'
# The local registry serves the packed 0.0.0 build, so create pins the
# exact version like a real release. The vp binary was built before the
# pack step pinned the package versions, so align the version explicitly.
VP_VERSION: '0.0.0'
# Force full dependency rewriting so the library template's existing
# vite-plus dep gets overridden with the local tgz
# vite-plus dep gets overridden with the local build
VP_FORCE_MIGRATE: '1'
# yarn 4 quarantines packages published within `npmMinimalAgeGate`
# (default 1440 min / 24h). When an oxlint bump landed <24h ago, the
Expand Down Expand Up @@ -221,10 +203,34 @@ jobs:
which vp
vp --version

- name: Start local npm registry
# Serve the packed local build behind a real registry interface for
# the create's install and every later step (the registry env is
# exported via GITHUB_ENV; the detached server lives for the job).
# Both output fds go to a file, not this step's pipes, so the step
# completes while the server keeps running.
run: |
node "$GITHUB_WORKSPACE/packages/tools/src/local-npm-registry.ts" --serve --packages-dir "$GITHUB_WORKSPACE/tmp/tgz" > "$RUNNER_TEMP/local-registry.out" 2>&1 &
Comment thread
fengmk2 marked this conversation as resolved.
server_pid=$!
until grep -q '"registry"' "$RUNNER_TEMP/local-registry.out" 2>/dev/null; do
if ! kill -0 "$server_pid" 2>/dev/null; then
echo "local registry failed to start:"
cat "$RUNNER_TEMP/local-registry.out"
exit 1
fi
sleep 0.2
done
handshake=$(head -1 "$RUNNER_TEMP/local-registry.out")
echo "$handshake"
echo "$handshake" | node -e 'const { env } = JSON.parse(require("node:fs").readFileSync(0, "utf8")); for (const [k, v] of Object.entries(env)) console.log(`${k}=${v}`)' >> "$GITHUB_ENV"

# No VP_OVERRIDE_PACKAGES: with VP_VERSION=0.0.0 the product default
# override map already pins `vite` to npm:@voidzero-dev/vite-plus-core@0.0.0
# and `vitest` to the bundled version (see VITE_PLUS_OVERRIDE_PACKAGES in
# packages/cli/src/utils/constants.ts), and stays correct across vitest
# bumps without editing this workflow.
- name: Run vp create ${{ matrix.template.name }} with ${{ matrix.package-manager }}
working-directory: ${{ runner.temp }}
env:
VP_OVERRIDE_PACKAGES: '{"vite":"file:${{ github.workspace }}/tmp/tgz/${{ env.VITE_OVERRIDE_TGZ }}","@voidzero-dev/vite-plus-core":"file:${{ github.workspace }}/tmp/tgz/voidzero-dev-vite-plus-core-0.0.0.tgz","vitest":"4.1.9","@vitest/expect":"4.1.9","@vitest/runner":"4.1.9","@vitest/snapshot":"4.1.9","@vitest/spy":"4.1.9","@vitest/utils":"4.1.9","@vitest/mocker":"4.1.9","@vitest/pretty-format":"4.1.9","@vitest/coverage-v8":"4.1.9","@vitest/coverage-istanbul":"4.1.9"}'
run: |
vp create ${{ matrix.template.create-args }} \
--no-interactive \
Expand Down Expand Up @@ -334,7 +340,7 @@ jobs:
fi
echo "✓ vite-plus, vite, vitest are all single instances"

- name: Verify local tgz packages installed
- name: Verify local packages installed
working-directory: ${{ runner.temp }}/test-project
run: |
node -e "
Expand Down Expand Up @@ -459,18 +465,23 @@ jobs:
if: matrix.template.name == 'monorepo'
working-directory: ${{ runner.temp }}/test-project
run: |
# Under npm, `vp run ready` reaches 100% cache hit only on the
# third invocation (#1638): vite-task's directory-listing
# Under npm and yarn, `vp run ready` reaches 100% cache hit only on
# the third invocation (#1638): vite-task's directory-listing
# fingerprint and fspy read/write tracking surface false-positive
# misses on run #2 because `packages/utils/node_modules/` is born
# during run #1. pnpm/yarn/bun pre-create per-package
# `node_modules/` at install time and reach 100% on run #2.
# during run #1. pnpm and bun pre-create per-package
# `node_modules/` at install time and reach 100% on run #2; Yarn
# Berry did too under the old file: overrides (per-package copies),
# but with registry-resolved semver specs it hoists the workspace
# deps like a real install, so it now behaves like npm here.
# The preceding `Verify project builds` step already invoked
# `vp run ready` once (verify-command for monorepo), so one
# extra warm-up here is enough under npm.
if [ "${{ matrix.package-manager }}" = "npm" ]; then
vp run ready >/dev/null 2>&1
fi
# extra warm-up here is enough.
case "${{ matrix.package-manager }}" in
npm|yarn)
vp run ready >/dev/null 2>&1
;;
esac
output=$(vp run ready 2>&1)
echo "$output"
if ! echo "$output" | grep -q 'cache hit (100%)'; then
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ vite-plus/
- **Generated project agent guidance**: `packages/cli/AGENTS.md` and `packages/cli/src/utils/agent.ts`; do not edit these when the task is only to improve root repo guidance.
- **Product/repo docs**: root contributor docs live at the repo root and the VitePress site under `docs/` (`docs/guide/`, `docs/config/`); generated agent guidance is separate.
- **CLI output behavior**: inspect the relevant code plus `packages/cli/snap-tests/` or `packages/cli/snap-tests-global/`.
- **Install-testing against the local build**: `packages/tools/src/local-npm-registry.ts` serves the packed checkout behind a real registry interface; used by install snap fixtures (`localVitePlusPackages`), ecosystem e2e (`ecosystem-ci/patch-project.ts`), and local `vp migrate`/`vp create` iteration (see `CONTRIBUTING.md`).

## Command and Config Model

Expand Down
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,29 @@ Verify the link with `ls -l node_modules/vite-plus` (it should be a symlink into
- `pnpm link` may also add a `packageManager` field to the test project's `package.json`; revert it if unwanted.
- Undo with `pnpm unlink vite-plus`, or remove the override and run `pnpm install`.

### Test `vp migrate` / `vp create` through a local npm registry

`pnpm link` swaps the code inside an existing project, but `vp migrate` and `vp create` pin the exact CLI version and then _install_ it, so the checkout's `vite-plus` / `@voidzero-dev/vite-plus-core` must be resolvable from a registry. `packages/tools/src/local-npm-registry.ts` provides that: it packs the checkout, serves the tarballs behind a real registry HTTP interface, and proxies every other package upstream. This replaces the old pkg.pr.new publish + registry-bridge round-trip for local iteration; you can verify migrate/create logic immediately after a build.

```bash
pnpm build # the served packages are built artifacts; rebuild after JS changes

# One-shot: wrap any command (from the project you want to migrate)
cd /path/to/test-project
node /path/to/vite-plus/packages/tools/src/local-npm-registry.ts --pack -- vp migrate --no-interactive
node /path/to/vite-plus/packages/tools/src/local-npm-registry.ts --pack -- vp create vite:application --no-interactive

# Or keep a server running for repeated commands (from the vite-plus checkout)
pnpm local-registry --pack --serve
# copy the printed `export ...` lines into the shell where you run vp
```

Notes:

- The served versions carry an old publish time, so `minimumReleaseAge` gates never quarantine them, and wrapped runs get throwaway Yarn Berry / bun caches (both cache registry state in ways that would otherwise leak stale local builds between runs).
- The same server backs the install snap fixtures (`localVitePlusPackages` in `steps.json`) and ecosystem e2e (`ecosystem-ci/patch-project.ts`), so a flow that works here works there too.
- `pnpm local-registry:ps` lists any registry processes still running (e.g. a `--serve` you forgot, or a wrapper that was killed mid-run); `pnpm local-registry:kill` stops them all and removes their leftover temp caches.

### Global CLI (Rust) changes

`pnpm link` only swaps the JS side; the `vp` binary on `PATH` (and the Rust-backed commands it handles directly, such as package-manager commands) is still whatever is installed in `~/.vite-plus`. For changes to the Rust global CLI (`crates/`), install it from source, and combine with `pnpm link` when the change spans both layers:
Expand Down
Loading
Loading