diff --git a/.claude/skills/release-manager/SKILL.md b/.claude/skills/release-manager/SKILL.md index ef7c7356f5..c9f37f3a25 100644 --- a/.claude/skills/release-manager/SKILL.md +++ b/.claude/skills/release-manager/SKILL.md @@ -48,6 +48,8 @@ gh workflow run prepare_release.yml --repo voidzero-dev/vite-plus -f version=X.Y The workflow bumps `packages/cli/package.json`, `packages/core/package.json`, `packages/prompts/package.json`, `packages/cli/binding/Cargo.toml`, and `crates/vp_global_cli/Cargo.toml`, refreshes `Cargo.lock`, and opens a PR titled `release: vX.Y.Z` from branch `release/vX.Y.Z`. The PR body ends with `Merging this PR will trigger the release workflow.` and that line must survive every later edit. +`@voidzero-dev/vite-plus-core` does not use `X.Y.Z`. Its version encodes the bundled Vite version (for example, `8.3.500` for Vite `8.3.5`; see [Core Version](../../../packages/core/BUNDLING.md#core-version)). The workflow selects it from the registry and names it in the first line of the PR body. In the steps below, `` is that version. Read it from the release branch with `node -p "require('./packages/core/package.json').version"`. + ## 2. Sync release versions (required every release) ### NAPI binding @@ -411,14 +413,15 @@ Auto-merge being enabled is not a completed merge. Confirm `mergedAt` and the me **When the `Release` job fails partway, fix the cause, then use "Re-run failed jobs", never "Re-run all jobs".** A full rerun repeats `check`, which now sees the new version on `unpkg.com/vite-plus@latest` and skips the whole release. A failed-jobs rerun reuses `check` and the build artifacts, and every npm publish step is idempotent: `.github/scripts/publish-npm-package.ts` skips versions the registry already serves (`@X.Y.Z is already published; skipping upload.`), so only the unpublished packages upload. Confirm that from the rerun log. The rerun waits on the `release` environment again, and whoever started the rerun cannot approve it. -**A successful publish command does not mean the packages are installable.** `pnpm publish` prints `✅ Published package @X.Y.Z` as soon as the registry accepts the request, and the registry can then take tens of minutes to actually serve that version. This has shipped a broken release: `vite-plus@X.Y.Z` went live on `latest` with an exact dependency on `@voidzero-dev/vite-plus-core@X.Y.Z` that was invisible for about 35 minutes, so every `npm install vite-plus` failed with `ETARGET` and both `publish-docker` and `Deploy docs` failed on `ERR_PNPM_NO_MATCHING_VERSION`. The downstream job failures are the symptom, not the cause; do not re-run them until the registry has the package. +**A successful publish command does not mean the packages are installable.** `pnpm publish` prints `✅ Published package @X.Y.Z` as soon as the registry accepts the request, and the registry can then take tens of minutes to actually serve that version. This has shipped a broken release: `vite-plus@X.Y.Z` went live on `latest` with an exact dependency on its `@voidzero-dev/vite-plus-core` version that was invisible for about 35 minutes, so every `npm install vite-plus` failed with `ETARGET` and both `publish-docker` and `Deploy docs` failed on `ERR_PNPM_NO_MATCHING_VERSION`. The downstream job failures are the symptom, not the cause; do not re-run them until the registry has the package. Check visibility directly, not through `npm view`, which caches: ```bash -for pkg in '@voidzero-dev%2Fvite-plus-core' 'vite-plus'; do - curl -s -H 'Cache-Control: no-cache' "https://registry.npmjs.org/$pkg?t=$(date +%s)" | - python3 -c "import json,sys;d=json.load(sys.stdin);print('$pkg', d['dist-tags'].get('latest'), 'X.Y.Z' in d['versions'])" +for entry in '@voidzero-dev%2Fvite-plus-core ' 'vite-plus X.Y.Z'; do + set -- $entry + curl -s -H 'Cache-Control: no-cache' "https://registry.npmjs.org/$1?t=$(date +%s)" | + python3 -c "import json,sys;d=json.load(sys.stdin);print('$1', d['dist-tags'].get('latest'), '$2' in d['versions'])" done ``` @@ -484,7 +487,8 @@ Local clients can also mislead in the other direction. npm and pnpm cache a look ```bash npm view vite-plus version # X.Y.Z - npm view @voidzero-dev/vite-plus-core version # X.Y.Z + npm view @voidzero-dev/vite-plus-core version # , which encodes the bundled Vite version + npm view vite-plus@X.Y.Z dependencies.vite # npm:@voidzero-dev/vite-plus-core@ npm view create-vite-plus version # X.Y.Z npm view @voidzero-dev/vite-plus-cli-darwin-arm64 version # X.Y.Z, spot-check a native platform package npm view vite-plus dist-tags.latest # X.Y.Z @@ -511,7 +515,7 @@ Local clients can also mislead in the other direction. npm and pnpm cache a look Require the target version directory, the expected `current` link, and `vp --version` output; a success message alone is insufficient. `Already up to date` passes only when the selected installation is already on the target version. - The Docker check must run `vp --version` inside the image, not just pull it: the output must report `vp vX.Y.Z`. Outside a project that output lists no bundled tools, so inspect the installed image package tree under `~/.vite-plus/X.Y.Z/node_modules/.pnpm` and confirm the bundled tool packages and versions match the changelog's Bundled Versions table. `tsdown` will be absent from that tree because it is bundled into `@voidzero-dev/vite-plus-core`; verify it with `npm view @voidzero-dev/vite-plus-core@X.Y.Z bundledVersions --json` instead. If no local Docker runtime is available, confirm `publish-docker` succeeded and inspect the GHCR manifest for both `linux/amd64` and `linux/arm64`. For the current stable release, confirm the version tag and `latest` have the same digest. Record each architecture's `vp --version` output from the Docker build logs when available (`gh api --allow-escape-sequences repos/voidzero-dev/vite-plus/actions/jobs//logs`; without the flag, `gh` refuses logs containing terminal escape sequences), and distinguish that evidence from a local run: + The Docker check must run `vp --version` inside the image, not just pull it: the output must report `vp vX.Y.Z`. Outside a project that output lists no bundled tools, so inspect the installed image package tree under `~/.vite-plus/X.Y.Z/node_modules/.pnpm` and confirm the bundled tool packages and versions match the changelog's Bundled Versions table. `tsdown` will be absent from that tree because it is bundled into `@voidzero-dev/vite-plus-core`; verify it with `npm view @voidzero-dev/vite-plus-core@ bundledVersions --json` instead. If no local Docker runtime is available, confirm `publish-docker` succeeded and inspect the GHCR manifest for both `linux/amd64` and `linux/arm64`. For the current stable release, confirm the version tag and `latest` have the same digest. Record each architecture's `vp --version` output from the Docker build logs when available (`gh api --allow-escape-sequences repos/voidzero-dev/vite-plus/actions/jobs//logs`; without the flag, `gh` refuses logs containing terminal escape sequences), and distinguish that evidence from a local run: ```bash TOKEN=$(curl -s "https://ghcr.io/token?scope=repository:voidzero-dev/vite-plus:pull" \ diff --git a/.github/scripts/__tests__/homebrew-formula.mjs b/.github/scripts/__tests__/homebrew-formula.mjs index 3b280a0c1a..b78520b545 100644 --- a/.github/scripts/__tests__/homebrew-formula.mjs +++ b/.github/scripts/__tests__/homebrew-formula.mjs @@ -6,6 +6,7 @@ import { test } from 'node:test'; import { fileURLToPath } from 'node:url'; import { + publishedCoreVersion, publishedFormulaVersion, releaseAssets, targets, @@ -143,3 +144,25 @@ await test('updates preserve recipe changes and reset only a previous version re /Unsafe formula URL/, ); }); + +await test('reads the core version from the published CLI alias', async () => { + const manifest = (dependencies) => async (url) => { + assert.equal(url, `https://registry.npmjs.org/vite-plus/${version}`); + return Response.json({ dependencies }); + }; + assert.equal( + await publishedCoreVersion( + version, + manifest({ vite: 'npm:@voidzero-dev/vite-plus-core@8.3.501' }), + ), + '8.3.501', + ); + await assert.rejects( + publishedCoreVersion(version, manifest({ vite: '^8.0.0' })), + /does not alias vite to @voidzero-dev\/vite-plus-core/, + ); + await assert.rejects( + publishedCoreVersion(version, async () => new Response('', { status: 404 })), + /HTTP 404/, + ); +}); diff --git a/.github/scripts/__tests__/upgrade-deps.spec.ts b/.github/scripts/__tests__/upgrade-deps.spec.ts index 75b7567350..d1ad856851 100644 --- a/.github/scripts/__tests__/upgrade-deps.spec.ts +++ b/.github/scripts/__tests__/upgrade-deps.spec.ts @@ -188,9 +188,11 @@ function createSyncFixture() { const metaDir = join(root, 'meta'); const versionsPath = join(metaDir, 'versions.json'); writeJson(corePath, { + version: '8.3.501', dependencies: { 'yuku-parser': '^0.9.3', postcss: '^8.5.6' }, optionalDependencies: { fsevents: '~2.3.3' }, devDependencies: { 'rolldown-plugin-dts': '^0.28.0' }, + bundledVersions: { vite: '8.3.5' }, }); writeJson(join(root, 'store/tsdown/package.json'), { name: 'tsdown', version: '0.23.0' }); writeJson(pluginPath, { @@ -216,6 +218,7 @@ function createSyncFixture() { dependencies: { 'yuku-codegen': '^0.8.1', 'yuku-parser': '^0.8.1' }, }); writeJson(vitePath, { + version: '8.3.5', dependencies: { postcss: '^8.5.28' }, optionalDependencies: { fsevents: '~2.4.0' }, }); @@ -239,9 +242,12 @@ test('pins the bundled parser, syncs Vite ranges, and preserves upgrade metadata const { corePath, versionsPath, metaDir, run } = fixture; run(); expect(readJson(corePath)).toEqual({ + // The bundled Vite did not change, so the release counter stays. + version: '8.3.501', dependencies: { 'yuku-parser': '0.10.3', postcss: '^8.5.28' }, optionalDependencies: { fsevents: '~2.4.0' }, devDependencies: { 'rolldown-plugin-dts': '^0.28.0' }, + bundledVersions: { vite: '8.3.5' }, }); expect(readJson(versionsPath)).toEqual({ oxlint: { old: '1.86.0', new: '1.87.0' }, @@ -271,6 +277,39 @@ test('pins the bundled parser, syncs Vite ranges, and preserves upgrade metadata expect(readFileSync(corePath, 'utf8')).toBe(before); }); +test('restarts the core version counter when the bundled Vite changes', () => { + const fixture = createSyncFixture(); + const { corePath, versionsPath, metaDir, run } = fixture; + writeJson(fixture.vitePath, { ...readJson(fixture.vitePath), version: '8.4.2' }); + run(); + expect(readJson(corePath).version).toBe('8.4.200'); + expect(readJson(corePath).bundledVersions).toEqual({ vite: '8.4.2' }); + expect(readJson(versionsPath)['@voidzero-dev/vite-plus-core']).toEqual({ + old: '8.3.501', + new: '8.4.200', + }); + expect(readFileSync(join(metaDir, 'pr-body.md'), 'utf8')).toContain( + '| `@voidzero-dev/vite-plus-core` | `8.3.501` | `8.4.200` |', + ); + + // A second pass keeps the recorded old version and the encoded version. + run(); + expect(readJson(corePath).version).toBe('8.4.200'); + expect(readJson(versionsPath)['@voidzero-dev/vite-plus-core']).toEqual({ + old: '8.3.501', + new: '8.4.200', + }); +}); + +test('fails without writing core when the Vite source has no version', () => { + const fixture = createSyncFixture(); + const { version: _, ...vite } = readJson(fixture.vitePath); + writeJson(fixture.vitePath, vite); + const before = readFileSync(fixture.corePath, 'utf8'); + expect(fixture.run).toThrow('Missing version'); + expect(readFileSync(fixture.corePath, 'utf8')).toBe(before); +}); + test('updates the parser pin when its installed version changes within the same range', () => { const { corePath, parserPath, versionsPath, run } = createSyncFixture(); run(); diff --git a/.github/scripts/update-homebrew-formula.mjs b/.github/scripts/update-homebrew-formula.mjs index ba7195d22f..edd97dcd00 100644 --- a/.github/scripts/update-homebrew-formula.mjs +++ b/.github/scripts/update-homebrew-formula.mjs @@ -5,7 +5,8 @@ import { readFile, writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; -import { waitForNpmPackagesFromEnv } from './wait-for-npm-packages.ts'; +import { CORE_ALIAS_PREFIX } from '../../packages/tools/src/core-version.ts'; +import { DEFAULT_NPM_REGISTRY, waitForNpmPackagesFromEnv } from './wait-for-npm-packages.ts'; export const targets = [ ['macos', 'arm', 'aarch64-apple-darwin', 'darwin-arm64'], @@ -105,15 +106,17 @@ export function updateFormula(source, version, assets) { return updated; } +async function download(url, fetchImpl) { + const response = await fetchImpl(url, { signal: AbortSignal.timeout(120_000) }); + assert.ok(response.ok, `Download failed: ${url} (HTTP ${response.status})`); + return response; +} + export async function verifyRelease(version, release, fetchImpl = fetch) { stableVersion(version); assert.equal(release.tag_name, `v${version}`); assert.ok(!release.draft && !release.prerelease, 'Release must be published and stable'); - const get = async (url) => { - const response = await fetchImpl(url, { signal: AbortSignal.timeout(120_000) }); - assert.ok(response.ok, `Download failed: ${url} (HTTP ${response.status})`); - return response; - }; + const get = (url) => download(url, fetchImpl); // The formula is added with the per-user Homebrew runtime. Check the release // tag, never main, before enabling installation. await get(`https://raw.githubusercontent.com/${repository}/v${version}/HomebrewFormula/vp.rb`); @@ -137,6 +140,24 @@ export async function verifyRelease(version, release, fetchImpl = fetch) { return assets; } +// The core version encodes the bundled Vite version, so it differs from the +// vite-plus version (rfcs/core-version-alignment.md). Read it from the `vite` +// alias of the published CLI. The release job publishes the CLI before this +// script runs. +export async function publishedCoreVersion( + version, + fetchImpl = fetch, + registry = process.env.PUBLISH_REGISTRY ?? DEFAULT_NPM_REGISTRY, +) { + const url = `${registry.replace(/\/+$/, '')}/vite-plus/${version}`; + const spec = (await (await download(url, fetchImpl)).json()).dependencies?.vite; + assert.ok( + typeof spec === 'string' && spec.startsWith(CORE_ALIAS_PREFIX), + `vite-plus@${version} does not alias vite to @voidzero-dev/vite-plus-core: ${spec}`, + ); + return spec.slice(CORE_ALIAS_PREFIX.length); +} + async function main() { const [version] = process.argv.slice(2); stableVersion(version ?? ''); @@ -145,14 +166,20 @@ async function main() { encoding: 'utf8', }), ); - const assets = await verifyRelease(version, release); + const [assets, coreVersion] = await Promise.all([ + verifyRelease(version, release), + publishedCoreVersion(version), + ]); const packages = [ - 'vite-plus', - '@voidzero-dev/vite-plus-core', - '@voidzero-dev/vite-plus-prompts', - ...targets.map(([, , , platform]) => `@voidzero-dev/vite-plus-${platform}`), + { name: 'vite-plus', version }, + { name: '@voidzero-dev/vite-plus-core', version: coreVersion }, + { name: '@voidzero-dev/vite-plus-prompts', version }, + ...targets.map(([, , , platform]) => ({ + name: `@voidzero-dev/vite-plus-${platform}`, + version, + })), ]; - await waitForNpmPackagesFromEnv(packages.map((name) => ({ name, version }))); + await waitForNpmPackagesFromEnv(packages); const file = new URL('../../HomebrewFormula/vp.rb', import.meta.url); const source = await readFile(file, 'utf8'); const result = updateFormula(source, version, assets); diff --git a/.github/scripts/upgrade-deps.ts b/.github/scripts/upgrade-deps.ts index 0927b3a9d2..573467e315 100644 --- a/.github/scripts/upgrade-deps.ts +++ b/.github/scripts/upgrade-deps.ts @@ -2,6 +2,11 @@ import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; +import { + CORE_PACKAGE_NAME, + encodeCoreVersion, + tryDecodeCoreVersion, +} from '../../packages/tools/src/core-version.ts'; import { findLatestStableVersionForMajor, getBundledDependencyRanges, @@ -533,10 +538,30 @@ function syncBundledDependencies(): void { recordChange(name, changes.get(name)?.old ?? oldRange, range); pkg[field][name] = range; } + syncCoreVersion(pkg); fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + '\n'); writeMetaFiles(); } +// The core version encodes the bundled Vite version (rfcs/core-version-alignment.md). +// When the bundled Vite changes, restart the release counter at 0. The release +// workflow selects the next unpublished counter. +function syncCoreVersion(pkg: { version?: unknown; bundledVersions?: Record }) { + const vitePath = path.join(ROOT, 'vite/packages/vite/package.json'); + const viteVersion = readJsonFile(vitePath).version; + if (typeof viteVersion !== 'string' || !viteVersion.trim()) { + throw new Error(`Missing version in ${vitePath}`); + } + pkg.bundledVersions = { ...pkg.bundledVersions, vite: viteVersion }; + const current = typeof pkg.version === 'string' ? pkg.version : undefined; + if (current !== undefined && tryDecodeCoreVersion(current)?.vite === viteVersion) { + return; + } + const next = encodeCoreVersion(viteVersion, 0); + recordChange(CORE_PACKAGE_NAME, changes.get(CORE_PACKAGE_NAME)?.old ?? current, next); + pkg.version = next; +} + async function upgradeDependencies(): Promise { console.log('Fetching latest versions…'); diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml index db7fd48e18..4263305ec1 100644 --- a/.github/workflows/prepare_release.yml +++ b/.github/workflows/prepare_release.yml @@ -38,14 +38,15 @@ jobs: # release.yml updates HomebrewFormula/vp.rb after the release archives and # their checksums are published. Do not point the tap at unpublished assets. - name: Bump versions + id: versions env: VERSION: ${{ inputs.version }} run: | set -euo pipefail update_json() { - local file=$1 - sed -i -E "s/^(\s*\"version\":\s*)\"[^\"]+\"/\1\"$VERSION\"/" "$file" - grep -qF "\"version\": \"$VERSION\"" "$file" || { echo "::error::Failed to update $file"; exit 1; } + local file=$1 version=${2:-$VERSION} + sed -i -E "s/^(\s*\"version\":\s*)\"[^\"]+\"/\1\"$version\"/" "$file" + grep -qF "\"version\": \"$version\"" "$file" || { echo "::error::Failed to update $file"; exit 1; } echo "Updated $file" } update_toml() { @@ -54,12 +55,17 @@ jobs: grep -qF "version = \"$VERSION\"" "$file" || { echo "::error::Failed to update $file"; exit 1; } echo "Updated $file" } + # The core version encodes the bundled Vite version and a release + # counter read from the registry (rfcs/core-version-alignment.md). + CORE_VERSION=$(node packages/tools/src/core-version.ts next --vite-plus "$VERSION") + echo "core-version=$CORE_VERSION" >> "$GITHUB_OUTPUT" update_json packages/cli/package.json - update_json packages/core/package.json + update_json packages/core/package.json "$CORE_VERSION" update_json packages/prompts/package.json update_json packages/create-vite-plus/package.json update_toml packages/cli/binding/Cargo.toml update_toml crates/vp_global_cli/Cargo.toml + node packages/tools/src/core-version.ts check --release - name: Refresh Cargo.lock run: cargo check @@ -81,7 +87,7 @@ jobs: base: main sign-commits: true body: | - Release vite-plus v${{ inputs.version }}. + Release vite-plus v${{ inputs.version }} with @voidzero-dev/vite-plus-core ${{ steps.versions.outputs.core-version }}. For a stable release, complete the `HomebrewFormula/vp.rb` update after publication by merging the generated `release/homebrew-v${{ inputs.version }}` PR. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f8d98162a..d671da3207 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,7 @@ jobs: outputs: version_changed: ${{ steps.version.outputs.changed }} version: ${{ steps.version.outputs.version }} + core_version: ${{ steps.core-version.outputs.version }} steps: - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 @@ -33,6 +34,12 @@ jobs: file-url: https://unpkg.com/vite-plus@latest/package.json file-name: packages/cli/package.json + # The core version encodes the bundled Vite version, so it differs from + # the CLI version (rfcs/core-version-alignment.md). + - name: Read core version + id: core-version + run: echo "version=$(node -p "require('./packages/core/package.json').version")" >> "$GITHUB_OUTPUT" + build-rust: name: Build bindings and binaries needs: check @@ -66,6 +73,7 @@ jobs: id-token: write # Required for OIDC env: VERSION: ${{ needs.check.outputs.version }} + CORE_VERSION: ${{ needs.check.outputs.core_version }} # npm publish-time scanning makes a successful upload temporarily # unavailable to installs. After each dependency tier becomes visible on # this runner's registry edge, allow time for other CDN edges to settle. @@ -91,6 +99,9 @@ jobs: - name: Install dependencies run: pnpm install + - name: Check core version + run: node packages/tools/src/core-version.ts check --release + - name: Download cli dist uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: @@ -182,7 +193,7 @@ jobs: - name: Publish core dependency tier run: >- node ./.github/scripts/publish-npm-package.ts - "@voidzero-dev/vite-plus-core@${VERSION}" + "@voidzero-dev/vite-plus-core@${CORE_VERSION}" -- pnpm publish --filter=./packages/core --tag latest --access public --no-git-checks @@ -191,7 +202,18 @@ jobs: - name: Wait for core to propagate run: >- node ./.github/scripts/wait-for-npm-packages.ts - "@voidzero-dev/vite-plus-core@${VERSION}" + "@voidzero-dev/vite-plus-core@${CORE_VERSION}" + + # A bundled Vite downgrade publishes a core version below the current + # latest. Show a wrong dist-tag without stopping the release. + - name: Check the core latest dist-tag + continue-on-error: true + run: | + LATEST=$(npm view @voidzero-dev/vite-plus-core dist-tags.latest) + if [ "$LATEST" != "$CORE_VERSION" ]; then + echo "::error::@voidzero-dev/vite-plus-core latest is $LATEST, expected $CORE_VERSION. Run: npm dist-tag add @voidzero-dev/vite-plus-core@$CORE_VERSION latest" + exit 1 + fi # Make the exact local CLI version installable without moving latest. # Bootstrap keeps selecting the previous release until its matching global @@ -288,7 +310,7 @@ jobs: ### Published Packages - - \`@voidzero-dev/vite-plus-core@${VERSION}\` + - \`@voidzero-dev/vite-plus-core@${CORE_VERSION}\` - \`vite-plus@${VERSION}\` - \`create-vite-plus@${VERSION}\` @@ -515,6 +537,7 @@ jobs: (needs.deploy-docs.result == 'success' || needs.deploy-docs.result == 'skipped') env: VERSION: ${{ needs.check.outputs.version }} + CORE_VERSION: ${{ needs.check.outputs.core_version }} IMAGE: ghcr.io/voidzero-dev/vite-plus steps: # Non-blocking: a webhook failure must not mark the release run as failed @@ -529,7 +552,7 @@ jobs: A new release is available! **Published Packages:** - • @voidzero-dev/vite-plus-core@${{ env.VERSION }} + • @voidzero-dev/vite-plus-core@${{ env.CORE_VERSION }} • vite-plus@${{ env.VERSION }} • create-vite-plus@${{ env.VERSION }} diff --git a/.github/workflows/reusable-ecosystem-ci.yml b/.github/workflows/reusable-ecosystem-ci.yml index df17337fcd..23f2bfd7c6 100644 --- a/.github/workflows/reusable-ecosystem-ci.yml +++ b/.github/workflows/reusable-ecosystem-ci.yml @@ -85,11 +85,15 @@ jobs: # and installs them like a real release, with every package manager # (including bun) resolving the standard # `vite -> npm:@voidzero-dev/vite-plus-core@` alias. Pin - # both packages to 0.0.0 so a correctly installed local build is + # the CLI to 0.0.0 and core to its local version (release counter + # 99, for example 8.3.599) 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) + # leaves packages/{core,cli} at a published version. The local core + # version still encodes the bundled Vite, so peer checks run as they + # do for a release (rfcs/core-version-alignment.md). + CORE_VERSION=$(node packages/tools/src/core-version.ts local) + (cd packages/core && npm pkg set version="$CORE_VERSION") (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 ../.. diff --git a/.github/workflows/reusable-release-build.yml b/.github/workflows/reusable-release-build.yml index 01d59394c5..b1c6948f6d 100644 --- a/.github/workflows/reusable-release-build.yml +++ b/.github/workflows/reusable-release-build.yml @@ -86,14 +86,17 @@ jobs: # cliPkg.version (VITE_PLUS_VERSION). Without this a preview # `vp migrate` pins the build-time release placeholder instead of # the test build, and skips the registry-bridge .npmrc. - # - packages/core: the release build bakes ${VERSION} into bundled - # Rolldown's binding version guards, matching the - # @voidzero-dev/vite-plus- packages published as - # ${VERSION}. A release checkout already carries ${VERSION}; this - # only changes preview builds. + # - packages/core: only for preview builds, which publish every + # package as 0.0.0-commit.. A release checkout already + # carries the core version, which encodes the bundled Vite + # version (rfcs/core-version-alignment.md). Release builds bake + # the CLI version into bundled Rolldown's binding version guards. # The list feeds the verify step below, so a stamped file cannot # silently drop out of verification. - PKG_JSON_STAMP_FILES="packages/cli/package.json packages/core/package.json" + PKG_JSON_STAMP_FILES="packages/cli/package.json" + if [[ "$VERSION" == 0.0.0-* ]]; then + PKG_JSON_STAMP_FILES="$PKG_JSON_STAMP_FILES packages/core/package.json" + fi for f in $PKG_JSON_STAMP_FILES; do pnpm exec json-edit "$f" '_.version = process.env.VERSION' done diff --git a/.github/workflows/test-vp-create.yml b/.github/workflows/test-vp-create.yml index 31ce989db7..bd47280ebd 100644 --- a/.github/workflows/test-vp-create.yml +++ b/.github/workflows/test-vp-create.yml @@ -107,11 +107,15 @@ jobs: # and installs them like a real release, with every package manager # (including bun) resolving the standard # `vite -> npm:@voidzero-dev/vite-plus-core@` alias. Pin - # both packages to 0.0.0 so a correctly installed local build is + # the CLI to 0.0.0 and core to its local version (release counter + # 99, for example 8.3.599) 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) + # version. The local core version still encodes the bundled Vite, + # so peer checks run as they do for a release + # (rfcs/core-version-alignment.md). + CORE_VERSION=$(node packages/tools/src/core-version.ts local) + (cd packages/core && npm pkg set version="$CORE_VERSION") (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 ../.. @@ -181,6 +185,7 @@ jobs: # 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. + # The "Set local core version" step sets VP_CORE_VERSION the same way. VP_VERSION: '0.0.0' # Force full dependency rewriting so the library template's existing # vite-plus dep gets overridden with the local build @@ -204,6 +209,9 @@ jobs: name: vite-plus-packages path: tmp/tgz + - name: Set local core version + run: echo "VP_CORE_VERSION=$(node packages/tools/src/core-version.ts local)" >> "$GITHUB_ENV" + - name: Install vp CLI run: | mkdir -p target/release @@ -238,8 +246,8 @@ jobs: 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 + # No VP_OVERRIDE_PACKAGES: with VP_CORE_VERSION set, the product default + # override map already pins `vite` to npm:@voidzero-dev/vite-plus-core@ # 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. diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 90fef2796d..6edaf31e23 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -24,6 +24,8 @@ pnpm add vite-plus@0.0.0-commit. The [release workflow](.github/workflows/release.yml) publishes platform packages before `@voidzero-dev/vite-plus-core`, then publishes `vite-plus`. It checks that the required package versions and tarballs are available before continuing to dependent steps. +`@voidzero-dev/vite-plus-core` has its own version, which encodes the bundled Vite version (for example, `8.3.500` for Vite `8.3.5`). The [prepare release workflow](.github/workflows/prepare_release.yml) selects it from the registry and prints both versions in the release PR. The platform packages, `vite-plus`, and `create-vite-plus` use the `vite-plus` version. See [Core Version](packages/core/BUNDLING.md#core-version). + The [propagation helper](.github/scripts/wait-for-npm-packages.ts) defaults to a 10-minute timeout and an additional 60-second wait for CDN propagation after availability checks pass. ### Recovering from a propagation timeout diff --git a/README.md b/README.md index 5f5db2fddd..9e08310875 100644 --- a/README.md +++ b/README.md @@ -203,11 +203,11 @@ If you are manually migrating a project to Vite+, install these dev dependencies vp install -D vite-plus ``` -Add package-manager overrides so that other packages use the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the installed `vite-plus` version. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest`. The project and `vp test` then use the same Vitest copy. Without the pin, a dependency or workspace package can install a different Vitest version. The two versions can use separate mocks, `expect` functions, and runner states: +Add package-manager overrides so that other packages use the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the core version that the installed `vite-plus` uses, shown by `vp toolchain vite-plus-core`. The core version encodes the bundled Vite version (for example, `8.3.500` for Vite `8.3.5`), so package managers check `vite` peer ranges against the bundled Vite. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest`. The project and `vp test` then use the same Vitest copy. Without the pin, a dependency or workspace package can install a different Vitest version. The two versions can use separate mocks, `expect` functions, and runner states: ```json "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` @@ -216,7 +216,7 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`: ```yaml overrides: - vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the installed vite-plus version + vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the version from vp toolchain vite-plus-core vitest@*: # Match the version from vp toolchain vitest ``` @@ -224,7 +224,7 @@ Or, if you are using Yarn: ```json "resolutions": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md index ad34531d72..27da3c19a3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_legacy_key/snapshots/command_update_catalog_protocol_legacy_key.md @@ -32,11 +32,6 @@ catalog: vite-plus: overrides: vite: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp up` @@ -85,11 +80,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp up` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md index 7de98a9cee..72b25fe774 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm/snapshots/command_update_catalog_protocol_pnpm.md @@ -60,9 +60,4 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md index 96f01d9165..9b738a2952 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_catalog_protocol_pnpm12/snapshots/command_update_catalog_protocol_pnpm12.md @@ -27,11 +27,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp up` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-api.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-api.mjs index 573b1212d6..04e308c94f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-api.mjs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-api.mjs @@ -24,6 +24,11 @@ for (const name of [ assert.equal(ModuleRunner, VpModuleRunner); const config = {}; assert.equal(vite.defineConfig(config), config); -assert.equal(pkg.dependencies.vite, `npm:@voidzero-dev/vite-plus-core@${pkg.version}`); +// The core version encodes the bundled Vite version, so it differs from the +// vite-plus version (rfcs/core-version-alignment.md). +assert.equal( + pkg.dependencies.vite, + `npm:@voidzero-dev/vite-plus-core@${require('vite/package.json').version}`, +); assert.equal(pkg.dependencies['@voidzero-dev/vite-plus-core'], undefined); console.log('Packed alias, ESM, CommonJS, and module-runner identity passed'); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-npm-layout.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-npm-layout.mjs index 7d71f37cc7..f984cfd3d4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-npm-layout.mjs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-npm-layout.mjs @@ -10,7 +10,11 @@ assert.equal(cliRequire('vite/package.json').name, '@voidzero-dev/vite-plus-core if (project.devDependencies.vite) { assert.equal( project.devDependencies.vite, - `npm:@voidzero-dev/vite-plus-core@${cliRequire('vite-plus/package.json').version}`, + cliRequire('vite-plus/package.json').dependencies.vite, + ); + assert.equal( + project.devDependencies.vite, + `npm:@voidzero-dev/vite-plus-core@${cliRequire('vite/package.json').version}`, ); assert.equal(require.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); assert.equal(vitestRequire.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); @@ -19,11 +23,10 @@ if (project.devDependencies.vite) { ); } else { assert.deepEqual(Object.keys(project.devDependencies), ['vite-plus']); - assert.equal(require('vite/package.json').name, 'vite'); - assert.equal(vitestRequire('vite/package.json').name, 'vite'); - assert.notEqual( - cliRequire.resolve('vite/package.json'), - vitestRequire.resolve('vite/package.json'), - ); - console.log('npm installed separate CLI core and upstream Vitest peer without overrides'); + // The core version encodes the bundled Vite version, so it satisfies Vitest's + // `vite` peer range. npm resolves that peer to the CLI's core instead of + // installing upstream Vite (rfcs/core-version-alignment.md). + assert.equal(require('vite/package.json').name, '@voidzero-dev/vite-plus-core'); + assert.equal(vitestRequire.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); + console.log('npm shares the CLI core with the Vitest peer without a project alias or overrides'); } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-tagged-alias.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-tagged-alias.mjs index 40e971754c..5b22621d02 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-tagged-alias.mjs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/check-tagged-alias.mjs @@ -1,24 +1,17 @@ import assert from 'node:assert/strict'; -import { spawnSync } from 'node:child_process'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const cliRequire = createRequire(require.resolve('vite-plus/package.json')); +const vitestRequire = createRequire(cliRequire.resolve('vitest/package.json')); const project = require('./package.json'); assert.equal(project.overrides, undefined); assert.equal(project.devDependencies.vite, 'npm:@voidzero-dev/vite-plus-core@latest'); -// npm 11.11 accepts a peer's upstream Vite as satisfying the tagged alias. -assert.equal(require('vite/package.json').name, 'vite'); -assert.equal(cliRequire('vite/package.json').name, '@voidzero-dev/vite-plus-core'); -assert.notEqual(require.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); - -for (const args of [['dev'], ['pack', 'entry.js']]) { - const result = spawnSync('vp', args, { encoding: 'utf8', timeout: 30_000 }); - assert.ifError(result.error); - const output = result.stdout + result.stderr; - assert.equal(result.status, 1, output); - assert.match(output, /Expected @voidzero-dev\/vite-plus-core@/); - assert.match(output, /but found vite@/); - assert.match(output, /Run `vp migrate` to align the Vite alias, then run `vp install`\./); - console.log(`vp ${args[0]} rejects the replaced npm alias and reports the repair command`); -} +// The core version encodes the bundled Vite version, so it satisfies Vitest's +// `vite` peer range and npm keeps the tagged alias on the core +// (rfcs/core-version-alignment.md). A `1.x` core made npm replace the alias +// with upstream Vite. +assert.equal(require('vite/package.json').name, '@voidzero-dev/vite-plus-core'); +assert.equal(require.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); +assert.equal(vitestRequire.resolve('vite/package.json'), cliRequire.resolve('vite/package.json')); +console.log('npm keeps the tagged core alias and shares it between the project, CLI, and Vitest'); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/pin-core-alias.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/pin-core-alias.mjs index b1e29e051d..bc0c30158a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/pin-core-alias.mjs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/pin-core-alias.mjs @@ -3,8 +3,10 @@ import { createRequire } from 'node:module'; // Before installation, resolve the checkout exposed by the snapshot runner. // CI can stamp its version, so do not hard-code the committed package version. +// The core version encodes the bundled Vite version, so it differs from the +// vite-plus version (rfcs/core-version-alignment.md). const require = createRequire(import.meta.url); -const { version } = require('vite-plus/package.json'); +const { version } = require('@voidzero-dev/vite-plus-core/package.json'); const project = JSON.parse(readFileSync('package.json', 'utf8')); project.devDependencies.vite = `npm:@voidzero-dev/vite-plus-core@${version}`; writeFileSync('package.json', `${JSON.stringify(project, null, 2)}\n`); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots.toml index d0be4f3f72..9de89704ba 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots.toml @@ -156,11 +156,13 @@ steps = [ ] [[case]] -name = "core_module_identity_npm_tagged_alias_rejected" +name = "core_module_identity_npm_tagged_alias" vp = "global" local-registry = true +comment = "The core version satisfies Vitest's vite peer range, so npm keeps a tagged core alias instead of replacing it with upstream Vite." steps = [ { argv = ["vpt", "write-file", "package.json", "{\"name\":\"core-module-identity\",\"private\":true,\"type\":\"module\",\"packageManager\":\"npm@11.11.0\",\"devDependencies\":{\"vite-plus\":\"latest\",\"vite\":\"npm:@voidzero-dev/vite-plus-core@latest\"}}\n"], snapshot = false }, { argv = ["vp", "install", "--ignore-scripts"], timeout = 120000, snapshot = false }, ["node", "check-tagged-alias.mjs"], + ["vp", "pack", "entry.js"], ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_cli_only_no_override.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_cli_only_no_override.md index 0571631515..3c9c60ff20 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_cli_only_no_override.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_cli_only_no_override.md @@ -13,7 +13,7 @@ ## `node check-npm-layout.mjs` ``` -npm installed separate CLI core and upstream Vitest peer without overrides +npm shares the CLI core with the Vitest peer without a project alias or overrides ``` ## `node check-bundled.mjs` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias.md new file mode 100644 index 0000000000..d47cbe8631 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias.md @@ -0,0 +1,28 @@ +# core_module_identity_npm_tagged_alias + +The core version satisfies Vitest's vite peer range, so npm keeps a tagged core alias instead of replacing it with upstream Vite. + +## `vpt write-file package.json '{"name":"core-module-identity","private":true,"type":"module","packageManager":"npm@11.11.0","devDependencies":{"vite-plus":"latest","vite":"npm:@voidzero-dev/vite-plus-core@latest"}} +'` + + +## `vp install --ignore-scripts` + + +## `node check-tagged-alias.mjs` + +``` +npm keeps the tagged core alias and shares it between the project, CLI, and Vitest +``` + +## `vp pack entry.js` + +``` +VITE+ - The Unified Toolchain for the Web + +ℹ entry: entry.js +ℹ Build start +ℹ dist/entry.mjs kB │ gzip: kB +ℹ 1 files, total: kB +✔ Build complete in +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias_rejected.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias_rejected.md deleted file mode 100644 index 8f3b5c664c..0000000000 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/core_module_identity/snapshots/core_module_identity_npm_tagged_alias_rejected.md +++ /dev/null @@ -1,15 +0,0 @@ -# core_module_identity_npm_tagged_alias_rejected - -## `vpt write-file package.json '{"name":"core-module-identity","private":true,"type":"module","packageManager":"npm@11.11.0","devDependencies":{"vite-plus":"latest","vite":"npm:@voidzero-dev/vite-plus-core@latest"}} -'` - - -## `vp install --ignore-scripts` - - -## `node check-tagged-alias.mjs` - -``` -vp dev rejects the replaced npm alias and reports the repair command -vp pack rejects the replaced npm alias and reports the repair command -``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md index 7121581f7a..4741c59d57 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_migrate_pnpm11/snapshots/create_approve_builds_migrate_pnpm11.md @@ -24,11 +24,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp create @your-org:with-build-dep --no-interactive --directory default-app` @@ -57,11 +52,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `cd default-app && vp pm approve-builds core-js` @@ -84,9 +74,4 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md index 6c8ca152cb..ab6923f9a7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_approve_builds_pnpm11/snapshots/create_approve_builds_pnpm11.md @@ -23,11 +23,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp create @your-org:with-build-dep --no-interactive --directory default-app` @@ -55,11 +50,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `cd default-app && vp pm approve-builds core-js` @@ -82,9 +72,4 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md index 5c05d098d5..ff75554728 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md @@ -46,11 +46,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vpt stat-file my-mono/.git --assert dir` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md index 54af3c6544..70d08e0758 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_add_git_hooks/snapshots/migration_add_git_hooks.md @@ -43,11 +43,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .vite-hooks/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md index d206896401..cba60fec73 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_auto_create_vite_config/snapshots/migration_auto_create_vite_config.md @@ -90,9 +90,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md index 786b036a0d..30052873dc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_baseurl_tsconfig/snapshots/migration_baseurl_tsconfig.md @@ -97,9 +97,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md index 41101ccc53..01c8723581 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_chained_lint_staged_pre_commit/snapshots/migration_chained_lint_staged_pre_commit.md @@ -48,11 +48,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md index 8f9a9de90b..1480398795 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_custom_dir/snapshots/migration_composed_husky_custom_dir.md @@ -57,11 +57,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .config/husky/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md index f3126ccd6e..aa852bfc34 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_composed_husky_prepare/snapshots/migration_composed_husky_prepare.md @@ -44,9 +44,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md index 8448cf35d6..a352df32bd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_env_prefix_lint_staged/snapshots/migration_env_prefix_lint_staged.md @@ -48,11 +48,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md index 6fd722d9e2..4124dc07f3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint/snapshots/migration_eslint.md @@ -44,11 +44,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file eslint.config.mjs --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md index 6e787aae18..ded31805d7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lint_staged/snapshots/migration_eslint_lint_staged.md @@ -41,11 +41,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md index 6bb47ada0e..38b2c8732d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_lintstagedrc/snapshots/migration_eslint_lintstagedrc.md @@ -41,11 +41,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .lintstagedrc.json --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md index cb125d95b5..c5600fa1cc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_eslint_npx_wrapper/snapshots/migration_eslint_npx_wrapper.md @@ -46,11 +46,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file eslint.config.mjs --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md index 38647dd192..f07e9d6bf3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky/snapshots/migration_existing_husky.md @@ -44,11 +44,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .husky/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md index fc0951692c..e560ba94cd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_lint_staged/snapshots/migration_existing_husky_lint_staged.md @@ -48,11 +48,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md index 45966828d4..464cce89a5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_hooks/snapshots/migration_existing_husky_v8_hooks.md @@ -45,11 +45,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .husky/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md index a6511ad5c9..29ffba5760 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_husky_v8_multi_hooks/snapshots/migration_existing_husky_v8_multi_hooks.md @@ -45,11 +45,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .husky/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md index 2729823751..4dc9ce6272 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_lint_staged_config/snapshots/migration_existing_lint_staged_config.md @@ -43,11 +43,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .lintstagedrc.json --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md index a40a4a8bb7..601711ff4d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_pnpm_exec_lint_staged/snapshots/migration_existing_pnpm_exec_lint_staged.md @@ -48,11 +48,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md index 4de69944ad..eb973a231e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_existing_prepare_script/snapshots/migration_existing_prepare_script.md @@ -44,11 +44,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .vite-hooks/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md index e715a94cef..7c3acb7133 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown/snapshots/migration_from_tsdown.md @@ -85,11 +85,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md index 7e226727f1..919b5e2bff 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsdown_json_config/snapshots/migration_from_tsdown_json_config.md @@ -86,11 +86,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md index bcd8c684ae..54cb5e435b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_config/snapshots/migration_from_vitest_config.md @@ -108,9 +108,7 @@ overrides: '@vitest/browser@*': peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md index 41978da470..f3a6324d81 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_vitest_files/snapshots/migration_from_vitest_files.md @@ -52,10 +52,8 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md index ef9b150f19..b18f3b41cd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_hooks_skip_on_existing_hookspath/snapshots/migration_hooks_skip_on_existing_hookspath.md @@ -43,11 +43,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `git config --local core.hooksPath` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md index 2d866471f8..13be0b56a2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_catalog_version/snapshots/migration_husky_catalog_version.md @@ -54,11 +54,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md index 70af6b9a4b..e86d5eb535 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag/snapshots/migration_husky_latest_dist_tag.md @@ -44,9 +44,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md index 2e5b05206c..1e8ec36dbe 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_latest_dist_tag_v9_installed/snapshots/migration_husky_latest_dist_tag_v9_installed.md @@ -48,9 +48,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md index 9b895203cb..a8b696566c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_or_prepare/snapshots/migration_husky_or_prepare.md @@ -48,9 +48,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md index 1cca97e5b1..eac86d09ef 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_semicolon_prepare/snapshots/migration_husky_semicolon_prepare.md @@ -48,9 +48,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md index b775701d03..c0460fd0b8 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_husky_v8_preserves_lint_staged/snapshots/migration_husky_v8_preserves_lint_staged.md @@ -48,9 +48,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md index 0f2a1951b1..236b092660 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lazy_plugins_await/snapshots/migration_lazy_plugins_await.md @@ -62,9 +62,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md index 467fd26f76..4775b5160b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_in_scripts/snapshots/migration_lint_staged_in_scripts.md @@ -49,11 +49,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md index 23fb3a8a00..b83bdbda3e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_merge_fail/snapshots/migration_lint_staged_merge_fail.md @@ -50,11 +50,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md index e13263d45d..4b03c89791 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lint_staged_ts_config/snapshots/migration_lint_staged_ts_config.md @@ -46,11 +46,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file lint-staged.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md index 4134ba0d43..b40631cf68 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_json/snapshots/migration_lintstagedrc_json.md @@ -98,11 +98,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md index fe4904d1e5..686ce20a82 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_merge_fail/snapshots/migration_lintstagedrc_merge_fail.md @@ -47,11 +47,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .lintstagedrc.json` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md index beff4d8795..ea662e0ec4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_not_support/snapshots/migration_lintstagedrc_not_support.md @@ -74,9 +74,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md index e3662eebe4..b768812354 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_lintstagedrc_staged_exists/snapshots/migration_lintstagedrc_staged_exists.md @@ -44,11 +44,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .lintstagedrc.json --assert file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md index 165f3445bf..029771df29 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_js/snapshots/migration_merge_vite_config_js.md @@ -84,9 +84,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md index 64ac0df171..097d14b181 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_merge_vite_config_ts/snapshots/migration_merge_vite_config_ts.md @@ -164,9 +164,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md index 9b74a136c7..6294fb9da8 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm/snapshots/migration_monorepo_pnpm.md @@ -135,10 +135,8 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' minimumReleaseAgeExclude: - vite-plus diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md index ab8dc31e0a..56cea89ad3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_monorepo_pnpm_overrides_dependency_selector/snapshots/migration_monorepo_pnpm_overrides_dependency_selector.md @@ -68,11 +68,6 @@ overrides: supertest>superagent: 9.0.2 react-click-away-listener>react: 0.0.0-experimental-7dc903cd-20251203 vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file packages/app/package.json` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md index cb103d8e0f..53df88e954 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_git_repo/snapshots/migration_no_git_repo.md @@ -39,11 +39,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .vite-hooks --assert dir` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md index 830b4912ea..d7d4cb3ee7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks/snapshots/migration_no_hooks.md @@ -39,11 +39,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .vite-hooks --assert-not dir` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md index 4d0cd34d8b..1405b4955a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_no_hooks_with_husky/snapshots/migration_no_hooks_with_husky.md @@ -48,11 +48,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .husky --assert-not dir` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md index 47b7ab55d9..5e1ad05ab6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_npmx_dev/snapshots/migration_npmx_dev.md @@ -16,6 +16,7 @@ VITE+ - The Unified Toolchain for the Web @vitest/browser-playwright 4.1.10 → @vitest/coverage-v8 4.1.10 → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -62,9 +63,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md index cade69a2f6..22c25bdfb1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_other_hook_tool/snapshots/migration_other_hook_tool.md @@ -48,9 +48,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md index 0bce7e8eea..bff0813631 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_json_with_comments/snapshots/migration_oxlintrc_json_with_comments.md @@ -81,9 +81,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md index 494f0ccc1d..424171ff34 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_oxlintrc_jsonc/snapshots/migration_oxlintrc_jsonc.md @@ -90,9 +90,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md index 97dd757d01..ea063b0541 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_installed_vite_plus/snapshots/migration_partially_installed_vite_plus.md @@ -60,11 +60,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md index 5bb81236bb..3b9ae80ad5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_partially_migrated_pre_commit/snapshots/migration_partially_migrated_pre_commit.md @@ -45,11 +45,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file .husky/pre-commit` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_playwright_test/snapshots/migration_playwright_test.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_playwright_test/snapshots/migration_playwright_test.md index 983c329bc3..7140b67dc1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_playwright_test/snapshots/migration_playwright_test.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_playwright_test/snapshots/migration_playwright_test.md @@ -16,6 +16,7 @@ VITE+ - The Unified Toolchain for the Web @vitest/browser-playwright 4.1.10 → @vitest/coverage-v8 4.1.10 → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -62,9 +63,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md index 2ad8880f7e..db43ba69cc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_preserve_below_policy_node_pins/snapshots/migration_preserve_below_policy_node_pins.md @@ -67,11 +67,6 @@ catalogs: vite-plus: overrides: vite@*: catalog:vite-stack -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md index bd736ea504..310f8c21df 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier/snapshots/migration_prettier.md @@ -45,11 +45,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .prettierrc.json --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md index 53f8b36cda..fbeab78a28 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_eslint_combo/snapshots/migration_prettier_eslint_combo.md @@ -47,11 +47,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file eslint.config.mjs --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md index 69ad496ca8..f4c973cccf 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_ignore_unknown/snapshots/migration_prettier_ignore_unknown.md @@ -45,11 +45,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt stat-file .prettierrc.json --assert-not file` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md index 09e6ef9c66..3d436e89e1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_lint_staged/snapshots/migration_prettier_lint_staged.md @@ -42,11 +42,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md index b0dd73997e..cf6f814751 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_prettier_pkg_json/snapshots/migration_prettier_pkg_json.md @@ -43,11 +43,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vpt print-file vite.config.ts` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md index 16d65ed4e1..de54e90796 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_rewrite_declare_module/snapshots/migration_rewrite_declare_module.md @@ -84,9 +84,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md index 6681cd8c83..c963c637ec 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_dependency/snapshots/migration_skip_vite_dependency.md @@ -74,9 +74,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md index 3e2ad38e8c..c6df351109 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_skip_vite_peer_dependency/snapshots/migration_skip_vite_peer_dependency.md @@ -74,9 +74,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_stale_vitest_alias_startup/snapshots/migration_stale_vitest_alias_startup.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_stale_vitest_alias_startup/snapshots/migration_stale_vitest_alias_startup.md index f07bedca24..21eb2332fe 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_stale_vitest_alias_startup/snapshots/migration_stale_vitest_alias_startup.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_stale_vitest_alias_startup/snapshots/migration_stale_vitest_alias_startup.md @@ -65,9 +65,4 @@ catalog: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md index 190803a2df..7f20f7781c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_pnpm/snapshots/migration_standalone_pnpm.md @@ -40,9 +40,4 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md index bea45e89e0..f8872f5d07 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_subpath/snapshots/migration_subpath.md @@ -69,9 +69,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md index 02ac9a1233..317e458361 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_tsconfig_esmoduleinterop/snapshots/migration_tsconfig_esmoduleinterop.md @@ -71,9 +71,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md index e2e816ce40..1ee7aa7d57 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_peer_only_pnpm/snapshots/migration_upgrade_browser_peer_only_pnpm.md @@ -13,6 +13,7 @@ VITE+ - The Unified Toolchain for the Web vite-plus latest → vite → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -56,10 +57,8 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md index bf85dc3a16..be418e27f8 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_source_only_pnpm/snapshots/migration_upgrade_browser_source_only_pnpm.md @@ -19,6 +19,7 @@ VITE+ - The Unified Toolchain for the Web vite → @vitest/browser 4.1.8 → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -59,9 +60,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migrate_vitest4_community_provider.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migrate_vitest4_community_provider.md index e118fff0f5..e0afce59c0 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migrate_vitest4_community_provider.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migrate_vitest4_community_provider.md @@ -17,6 +17,7 @@ VITE+ - The Unified Toolchain for the Web ◇ Migrated . to Vite+ • Node pnpm • 1 file had imports rewritten +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md index f6184c755f..2264e3d0cf 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/migration_upgrade_browser_webdriverio_pnpm.md @@ -19,6 +19,7 @@ VITE+ - The Unified Toolchain for the Web vite → • 1 file had imports rewritten • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -77,10 +78,8 @@ overrides: '@vitest/browser@*': peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' allowBuilds: edgedriver: true diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/preserve_community_provider_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/preserve_community_provider_version.md index 621f76c9c2..0eff0f5412 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/preserve_community_provider_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/preserve_community_provider_version.md @@ -18,6 +18,7 @@ VITE+ - The Unified Toolchain for the Web vite → • 1 file had imports rewritten • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/upgrade_community_provider_catalog.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/upgrade_community_provider_catalog.md index 69a21053b2..f93ad80924 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/upgrade_community_provider_catalog.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_browser_webdriverio_pnpm/snapshots/upgrade_community_provider_catalog.md @@ -75,10 +75,8 @@ allowBuilds: geckodriver: true peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_hooks_flag_pnpm/snapshots/migration_upgrade_hooks_flag_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_hooks_flag_pnpm/snapshots/migration_upgrade_hooks_flag_pnpm.md index 6974febf41..8e1a3d1342 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_hooks_flag_pnpm/snapshots/migration_upgrade_hooks_flag_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_hooks_flag_pnpm/snapshots/migration_upgrade_hooks_flag_pnpm.md @@ -18,6 +18,7 @@ VITE+ - The Unified Toolchain for the Web • 2 config updates applied • Git hooks configured • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `git config --local core.hooksPath` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md index a095fef1db..28c87514c2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_monorepo_vitest_localized_pnpm/snapshots/migration_upgrade_monorepo_vitest_localized_pnpm.md @@ -13,6 +13,7 @@ VITE+ - The Unified Toolchain for the Web vite-plus latest → vite → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -68,9 +69,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md index 465554a573..fe95d68337 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_nuxt_test_utils_monorepo/snapshots/migration_upgrade_nuxt_test_utils_monorepo.md @@ -62,10 +62,8 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md index 15698124cc..a3a367b082 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_peer_vitest_catalog_pnpm/snapshots/migration_upgrade_peer_vitest_catalog_pnpm.md @@ -13,6 +13,7 @@ VITE+ - The Unified Toolchain for the Web vite-plus latest → vite → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -50,11 +51,6 @@ catalogs: test: {} overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md index 9e63d36f5e..ee30c7c0aa 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_bundled_catalog_dep/snapshots/migration_upgrade_pnpm_bundled_catalog_dep.md @@ -49,9 +49,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md index 1cb71f44bd..32b831b67c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_pnpm_catalogs_default/snapshots/migration_upgrade_pnpm_catalogs_default.md @@ -52,11 +52,6 @@ catalogs: rari: ^0.14.12 overrides: vite@*: catalog:build -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` @@ -106,9 +101,4 @@ catalogs: rari: ^0.14.12 overrides: vite@*: catalog:build -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_full_pnpm/snapshots/migration_upgrade_setup_full_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_full_pnpm/snapshots/migration_upgrade_setup_full_pnpm.md index a8618adbf1..145033fe63 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_full_pnpm/snapshots/migration_upgrade_setup_full_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_full_pnpm/snapshots/migration_upgrade_setup_full_pnpm.md @@ -22,6 +22,7 @@ VITE+ - The Unified Toolchain for the Web • 2 config updates applied • Node version manager file migrated to .node-version • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite → Manual follow-up: - Remove the "volta" field from package.json ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md index 227c579723..69513ff898 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_setup_skipped_default_pnpm/snapshots/migration_upgrade_setup_skipped_default_pnpm.md @@ -13,6 +13,7 @@ VITE+ - The Unified Toolchain for the Web vite-plus 0.1.21 → vite → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite • Skipped editor, hooks, and lint setup. Run `vp migrate --full` to apply them. ``` @@ -47,11 +48,6 @@ pnpm settings consolidated by the version upgrade ``` overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md index e02b10c9fb..9e2e00f978 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_stale_local_pnpm/snapshots/migration_upgrade_stale_local_pnpm.md @@ -16,6 +16,7 @@ VITE+ - The Unified Toolchain for the Web vite-plus 0.1.24 → vite → • Package manager settings configured +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -46,11 +47,6 @@ pnpm settings should be consolidated here ``` overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' catalog: vite: npm:@voidzero-dev/vite-plus-core@ vite-plus: diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md index 3ace8f239c..f5ba43cf8c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_upgrade_vitest_reference_whitespace_pnpm/snapshots/migration_upgrade_vitest_reference_whitespace_pnpm.md @@ -10,6 +10,7 @@ VITE+ - The Unified Toolchain for the Web ◇ Migrated . to Vite+ • Node pnpm • 2 config updates applied, 1 file had imports rewritten +• Removed `vite` from pnpm peerDependencyRules: the core version now matches the bundled Vite ``` ## `vpt print-file package.json` @@ -54,11 +55,6 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` ## `vp migrate --no-interactive` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md index d038952dc4..16c8fcc19a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_plus_in_dependencies_pnpm/snapshots/migration_vite_plus_in_dependencies_pnpm.md @@ -45,9 +45,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md index 2e5cc07b7f..6f965f0493 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vite_version/snapshots/migration_vite_version.md @@ -41,9 +41,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md index d20d676a0a..85efefa5b0 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_import_only/snapshots/migration_vitest_import_only.md @@ -50,9 +50,4 @@ catalog: vite-plus: overrides: vite@*: 'catalog:' -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md index f67ce74fd3..56e0db8748 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_vitest_peer_dep/snapshots/migration_vitest_peer_dep.md @@ -51,9 +51,7 @@ overrides: vitest@*: 'catalog:' peerDependencyRules: allowAny: - - vite - vitest allowedVersions: - vite: '*' vitest: '*' ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_members/snapshots/migration_workspace_members.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_members/snapshots/migration_workspace_members.md index 8add5c6b23..63182370c6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_members/snapshots/migration_workspace_members.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_members/snapshots/migration_workspace_members.md @@ -27,11 +27,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vp run -r build` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md index bb258b1685..8057d0a2e4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots/new_vite_monorepo.md @@ -93,11 +93,6 @@ catalog: vite-plus: overrides: vite@*: "catalog:" -peerDependencyRules: - allowAny: - - vite - allowedVersions: - vite: "*" ``` ## `vpt stat-file vite-plus-monorepo/.gitignore --assert file` diff --git a/docs/guide/local-cli.md b/docs/guide/local-cli.md index c2a76e9b93..5a055eecfd 100644 --- a/docs/guide/local-cli.md +++ b/docs/guide/local-cli.md @@ -61,26 +61,26 @@ bun add -D vite-plus ::: -Add overrides to your package manager so that other packages resolve the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the installed `vite-plus` version. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest` so the whole project shares a single Vitest copy with `vp test`. Without the `vitest` pin, a dependency or workspace package can pull a different Vitest than the bundled runner, splitting Vitest's internals (mocks, `expect`, runner state): +Add overrides to your package manager so that other packages resolve the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the core version that the installed `vite-plus` uses, shown by `vp toolchain vite-plus-core`. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest` so the whole project shares a single Vitest copy with `vp test`. Without the `vitest` pin, a dependency or workspace package can pull a different Vitest than the bundled runner, splitting Vitest's internals (mocks, `expect`, runner state): ::: code-group ```yaml [pnpm-workspace.yaml] overrides: - vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the installed vite-plus version + vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the version from vp toolchain vite-plus-core vitest@*: # Match the version from vp toolchain vitest ``` ```json [npm / Bun package.json] "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` ```json [Yarn package.json] "resolutions": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` @@ -95,11 +95,11 @@ For example, update an existing `vite` development dependency as follows. Keep t ```json [package.json] { "devDependencies": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vite-plus": "" }, "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } } @@ -113,9 +113,10 @@ If you also declare `vitest` directly, set its dependency entry to the exact ver Dependencies and plugins can import `vite` or `vitest` directly, even when your own code imports from `vite-plus`. These overrides align their dependencies with the toolchain Vite+ uses: - The `vite` alias directs those imports to Vite+'s core package. Separate Vite instances can break runtime identity checks: [issue #1391](https://github.com/voidzero-dev/vite-plus/issues/1391) reported TanStack Start returning 404s because an `instanceof` check crossed two copies. [PR #2617](https://github.com/voidzero-dev/vite-plus/pull/2617) addresses the CLI side by sharing Vite through the same alias. +- The core version encodes the bundled Vite version. Its major and minor are the Vite major and minor, and its patch is the Vite patch times 100 plus a release counter. For example, core `8.3.500` bundles Vite `8.3.5`. Package managers compare this version with the `vite` peer ranges of plugins, so a plugin that supports the bundled Vite passes the check, and a plugin that does not support it still gets a peer warning. [Issue #2806](https://github.com/voidzero-dev/vite-plus/issues/2806) describes the earlier `1.x` versions, which failed every check. - The exact `vitest` pin keeps dependencies and `vp test` on the same Vitest version, avoiding separate mocks, `expect` instances, and runner state. [PR #2365](https://github.com/voidzero-dev/vite-plus/pull/2365) documents this requirement for manual installation. -Keep the core alias aligned with your installed `vite-plus` version and update the Vitest pin to match its bundled version when upgrading. [Issue #2356](https://github.com/voidzero-dev/vite-plus/issues/2356) describes how dependency bots can update these packages independently and leave incompatible versions installed together. +Keep the core alias aligned with the core version of your installed `vite-plus` and update the Vitest pin to match its bundled version when upgrading. [Issue #2356](https://github.com/voidzero-dev/vite-plus/issues/2356) describes how dependency bots can update these packages independently and leave incompatible versions installed together. ::: diff --git a/docs/guide/migrate-rules.md b/docs/guide/migrate-rules.md index c37dcf3c13..afdc45005e 100644 --- a/docs/guide/migrate-rules.md +++ b/docs/guide/migrate-rules.md @@ -379,6 +379,13 @@ Migration converts the Volta `volta.node` pin to `.node-version`, because Vite+ - pnpm accepts the logical default catalog as either top-level `catalog` or `catalogs.default`, but not both. Migration preserves the existing form and never creates the other form beside it. - When an existing named catalog already owns `vite-plus`, `vite`, or `vitest`, migration reuses that managed toolchain catalog for newly added dependencies and overrides. It creates a top-level default catalog only when no managed or default catalog can be reused. +**Peer rules.** The core version encodes the bundled Vite version: core `8.3.500` bundles Vite `8.3.5` (see the [RFC](https://github.com/voidzero-dev/vite-plus/blob/main/rfcs/core-version-alignment.md)). pnpm checks `vite` peer ranges against the `vite` alias, so a plugin that supports the bundled Vite passes, and a plugin that does not support it fails. + +- Migration does not add `vite` to `peerDependencyRules.allowAny` or `peerDependencyRules.allowedVersions`. +- Migration removes an existing `vite` entry from both fields, also an entry that you wrote. The only purpose of that entry was to accept the `1.x` core alias. It removes a field, or `peerDependencyRules`, when no entry remains. Other entries stay. The migrate summary names the removed rule. +- For a preview build (`0.0.0-commit.`) or a Vite+ prerelease core (such as `8.4.0-vp.0`), migration keeps writing the `vite` rule. Package managers do not accept these versions for ranges such as `^8.0.0`. +- After migration, a plugin whose `vite` peer range excludes the bundled Vite (for example `^7.0.0`) produces a peer warning. With `strictPeerDependencies`, the install fails. Update the plugin, or add a rule scoped to that plugin, such as `allowedVersions: { 'vite-plugin-foo>vite': '*' }`. Migration removes only the plain `vite` key. + **Other rules.** - Packages that use `vite-plus` without a direct `vite` declaration keep that layout (see [Vite and Overrides](#vite-and-overrides)). diff --git a/docs/guide/upgrade-project.md b/docs/guide/upgrade-project.md index 8b32e058fb..efec5a0d4f 100644 --- a/docs/guide/upgrade-project.md +++ b/docs/guide/upgrade-project.md @@ -18,7 +18,7 @@ On a project that is already on Vite+, migrate does a toolchain version upgrade ## Manually Updating -Update `vite-plus` and the `vite` alias to `@voidzero-dev/vite-plus-core` together, keeping the core version aligned with `vite-plus`. Update these entries wherever they are declared in your workspace, including overrides or catalogs, then install dependencies to refresh the lockfile. Also [update the Vitest pin](#updating-the-vitest-pin) to match the bundled version. +Update `vite-plus` and the `vite` alias to `@voidzero-dev/vite-plus-core` together. The two packages have different versions: the core version encodes the bundled Vite version (for example, `8.3.500` for Vite `8.3.5`). After you update `vite-plus`, set the alias to the version that `vp toolchain vite-plus-core` shows. Update these entries wherever they are declared in your workspace, including overrides or catalogs, then install dependencies to refresh the lockfile. Also [update the Vitest pin](#updating-the-vitest-pin) to match the bundled version. Without the global CLI, run the `vp` commands on this page through your package manager, for example `pnpm exec vp toolchain vitest`. diff --git a/ecosystem-ci/patch-project.ts b/ecosystem-ci/patch-project.ts index 6cd4700203..65b5fbaabd 100644 --- a/ecosystem-ci/patch-project.ts +++ b/ecosystem-ci/patch-project.ts @@ -6,7 +6,7 @@ import { join } from 'node:path'; import { VITEST_VERSION } from '../packages/cli/src/utils/constants.ts'; import vitePlusCorePkg from '../packages/core/package.json' with { type: 'json' }; import { patchNpmxVitestConfig } from './npmx.ts'; -import { ecosystemCiDir, tgzDir, vitePlusTgzVersion } from './paths.ts'; +import { ecosystemCiDir, tgzDir, vitePlusCoreTgzVersion, vitePlusTgzVersion } from './paths.ts'; import repos from './repo.json' with { type: 'json' }; import { prepareWebdriverioProject } from './webdriverio.ts'; @@ -31,6 +31,7 @@ const cli = process.env.VP_CLI_BIN ?? 'vp'; // (local-npm-registry.ts), so vp migrate pins and installs the checkout's // own version through the standard registry code paths, with no `file:` specs. const vitePlusVersion = vitePlusTgzVersion(); +const vitePlusCoreVersion = vitePlusCoreTgzVersion(); const registryScript = join( import.meta.dirname, @@ -319,7 +320,7 @@ const migrateEnv: NodeJS.ProcessEnv = { ...registryInfo.env, ...(forceFreshMigration ? { VP_FORCE_MIGRATE: '1' } : {}), VP_OVERRIDE_PACKAGES: JSON.stringify({ - vite: `npm:@voidzero-dev/vite-plus-core@${vitePlusVersion}`, + vite: `npm:@voidzero-dev/vite-plus-core@${vitePlusCoreVersion}`, ...vitestOverrides, }), // The vp binary was built before the pack step pinned the package versions, diff --git a/ecosystem-ci/paths.ts b/ecosystem-ci/paths.ts index d6e2c3b118..6d4c865cf6 100644 --- a/ecosystem-ci/paths.ts +++ b/ecosystem-ci/paths.ts @@ -20,11 +20,24 @@ export const tgzDir = join(projectDir, '..', 'tmp', 'tgz'); * version on a local run. */ export function vitePlusTgzVersion(): string { + return tgzVersion('vite-plus'); +} + +/** + * The version of the packed core tgz. It encodes the bundled Vite version, so + * it differs from {@link vitePlusTgzVersion} (rfcs/core-version-alignment.md). + */ +export function vitePlusCoreTgzVersion(): string { + return tgzVersion('voidzero-dev-vite-plus-core'); +} + +function tgzVersion(prefix: string): string { + const pattern = new RegExp(`^${prefix}-(\\d.*)\\.tgz$`); const version = readdirSync(tgzDir) - .map((entry) => /^vite-plus-(\d.*)\.tgz$/.exec(entry)?.[1]) + .map((entry) => pattern.exec(entry)?.[1]) .find(Boolean); if (!version) { - throw new Error(`No vite-plus-.tgz found in ${tgzDir}`); + throw new Error(`No ${prefix}-.tgz found in ${tgzDir}`); } return version; } diff --git a/packages/cli/BUNDLING.md b/packages/cli/BUNDLING.md index ae3c70c5d5..49bb00e8f6 100644 --- a/packages/cli/BUNDLING.md +++ b/packages/cli/BUNDLING.md @@ -22,17 +22,23 @@ its subpaths. This gives the CLI and plugins the same dependency name and avoids separate core instances under the alias and canonical package name. `resolve-core.ts` resolves the alias from the selected CLI package and checks -its core version. It also checks any Vite dependency declared by the command's -target project. An incidental hoisted peer does not trigger project validation. -These checks run before Vite or packaging commands start. Keep the canonical -name in release metadata and alias targets to identify the published package. +that the core version matches the exact alias in the CLI manifest. The core +version encodes the bundled Vite version, so it differs from the CLI version +(see [Core Version](../core/BUNDLING.md#core-version)). It also checks any Vite +dependency declared by the command's target project. An incidental hoisted peer +does not trigger project validation. These checks run before Vite or packaging +commands start. Keep the canonical name in release metadata and alias targets +to identify the published package. For npm projects without overrides, pin a declared `vite` alias to the exact -installed `vite-plus` version. npm can replace a tagged alias such as -`npm:@voidzero-dev/vite-plus-core@latest` with upstream Vite to satisfy Vitest's -peer range. The CLI rejects that mismatch and directs users to `vp migrate`, -which writes an exact alias and the package-manager overrides. The npm fixtures -check shared core identity with an exact alias and rejection of the tagged layout. +core version that the installed `vite-plus` uses. With a `1.x` core, npm +replaced a tagged alias such as `npm:@voidzero-dev/vite-plus-core@latest` with +upstream Vite to satisfy Vitest's peer range. The encoded core version +satisfies that range, so npm now keeps the alias on the core. The CLI still +rejects upstream Vite and a core version that differs from its alias, and +directs users to `vp migrate`, which writes an exact alias and the +package-manager overrides. The npm fixtures check shared core identity with an +exact alias, a tagged alias, and no project alias. ## Build Steps diff --git a/packages/cli/README.md b/packages/cli/README.md index b70e87a3ea..c75fd08e08 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -198,11 +198,11 @@ If you are manually migrating a project to Vite+, install these dev dependencies vp install -D vite-plus ``` -Add package-manager overrides so that other packages use the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the installed `vite-plus` version. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest`. The project and `vp test` then use the same Vitest copy. Without the pin, a dependency or workspace package can install a different Vitest version. The two versions can use separate mocks, `expect` functions, and runner states: +Add package-manager overrides so that other packages use the Vite+ versions. Alias `vite` to `@voidzero-dev/vite-plus-core`, setting `` to the core version that the installed `vite-plus` uses, shown by `vp toolchain vite-plus-core`. The core version encodes the bundled Vite version (for example, `8.3.500` for Vite `8.3.5`), so package managers check `vite` peer ranges against the bundled Vite. Pin `vitest` to ``, using the bundled version shown by `vp toolchain vitest`. The project and `vp test` then use the same Vitest copy. Without the pin, a dependency or workspace package can install a different Vitest version. The two versions can use separate mocks, `expect` functions, and runner states: ```json "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` @@ -211,7 +211,7 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`: ```yaml overrides: - vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the installed vite-plus version + vite@*: npm:@voidzero-dev/vite-plus-core@ # Match the version from vp toolchain vite-plus-core vitest@*: # Match the version from vp toolchain vitest ``` @@ -219,7 +219,7 @@ Or, if you are using Yarn: ```json "resolutions": { - "vite": "npm:@voidzero-dev/vite-plus-core@", + "vite": "npm:@voidzero-dev/vite-plus-core@", "vitest": "" } ``` diff --git a/packages/cli/src/__tests__/resolve-core.spec.ts b/packages/cli/src/__tests__/resolve-core.spec.ts index 8e533913dd..86cb6dfc2a 100644 --- a/packages/cli/src/__tests__/resolve-core.spec.ts +++ b/packages/cli/src/__tests__/resolve-core.spec.ts @@ -5,9 +5,14 @@ import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import corePkg from '../../../core/package.json' with { type: 'json' }; import cliPkg from '../../package.json' with { type: 'json' }; import { resolveCore } from '../resolve-core.ts'; +// The core version encodes the bundled Vite version, so it differs from the +// CLI version (rfcs/core-version-alignment.md). +const CORE_VERSION = corePkg.version; + function writePackageJson(directory: string, manifest: Record): void { mkdirSync(directory, { recursive: true }); writeFileSync(join(directory, 'package.json'), JSON.stringify(manifest)); @@ -16,7 +21,7 @@ function writePackageJson(directory: string, manifest: Record): function writeCore( directory: string, name = '@voidzero-dev/vite-plus-core', - version = cliPkg.version, + version = CORE_VERSION, ): void { writePackageJson(directory, { name, @@ -27,10 +32,15 @@ function writeCore( writeFileSync(join(directory, 'pack.js'), ''); } -function writeCli(directory: string, version = cliPkg.version): void { +function writeCli( + directory: string, + version = cliPkg.version, + viteSpec = `npm:@voidzero-dev/vite-plus-core@${CORE_VERSION}`, +): void { writePackageJson(directory, { name: 'vite-plus', version, + dependencies: { vite: viteSpec }, exports: { './package.json': './package.json' }, }); } @@ -46,7 +56,7 @@ describe('resolveCore', () => { root = realpathSync(mkdtempSync(join(tmpdir(), 'vp-core-resolver-'))); project = join(root, 'project'); writePackageJson(project, { - devDependencies: { vite: `npm:@voidzero-dev/vite-plus-core@${cliPkg.version}` }, + devDependencies: { vite: `npm:@voidzero-dev/vite-plus-core@${CORE_VERSION}` }, }); cliModule = join(root, 'cli', 'dist', 'bin.js'); bundled = join(root, 'cli', 'node_modules', 'vite'); @@ -88,29 +98,62 @@ describe('resolveCore', () => { expect(resolveCore('', project, cliModule)).toBe(join(bundled, 'index.js')); }); - it.each(['0.0.0', '0.0.0-commit.1234567'])( - 'uses the installed CLI manifest after repacking as %s', - (version) => { - writeCli(join(root, 'cli'), version); - writeCore(bundled, '@voidzero-dev/vite-plus-core', version); - writeCore(projectCore, '@voidzero-dev/vite-plus-core', version); - expect(resolveCore('', project, cliModule)).toBe(join(bundled, 'index.js')); - expect(resolveCore('/pack', project, cliModule)).toBe(join(bundled, 'pack.js')); - }, - ); + it.each([ + ['0.0.0', '8.3.599'], + ['0.0.0-commit.1234567', '0.0.0-commit.1234567'], + ])('uses the installed CLI manifest after repacking as %s', (version, coreVersion) => { + writeCli(join(root, 'cli'), version, `npm:@voidzero-dev/vite-plus-core@${coreVersion}`); + writeCore(bundled, '@voidzero-dev/vite-plus-core', coreVersion); + writeCore(projectCore, '@voidzero-dev/vite-plus-core', coreVersion); + expect(resolveCore('', project, cliModule)).toBe(join(bundled, 'index.js')); + expect(resolveCore('/pack', project, cliModule)).toBe(join(bundled, 'pack.js')); + }); it.each(['project', 'bundled'])( 'still rejects a mismatched %s core after repacking the CLI', (location) => { - writeCli(join(root, 'cli'), '0.0.0'); - writeCore(bundled, '@voidzero-dev/vite-plus-core', '0.0.0'); + writeCli(join(root, 'cli'), '0.0.0', 'npm:@voidzero-dev/vite-plus-core@8.3.599'); + writeCore(bundled, '@voidzero-dev/vite-plus-core', '8.3.599'); writeCore(location === 'project' ? projectCore : bundled); expect(() => resolveCore('', project, cliModule)).toThrow( - `Expected @voidzero-dev/vite-plus-core@0.0.0, but found @voidzero-dev/vite-plus-core@${cliPkg.version}`, + `Expected @voidzero-dev/vite-plus-core@8.3.599, but found @voidzero-dev/vite-plus-core@${CORE_VERSION}`, ); }, ); + it('rejects a core that matches the CLI version instead of its alias', () => { + writeCore(bundled, '@voidzero-dev/vite-plus-core', cliPkg.version); + expect(() => resolveCore('', project, cliModule)).toThrow( + `Expected @voidzero-dev/vite-plus-core@${CORE_VERSION}, but found @voidzero-dev/vite-plus-core@${cliPkg.version}`, + ); + }); + + describe('with the repository workspace spec', () => { + beforeEach(() => { + writeCli(join(root, 'cli'), cliPkg.version, 'workspace:@voidzero-dev/vite-plus-core@*'); + writeCore(bundled, '@voidzero-dev/vite-plus-core', '0.0.0-any'); + }); + + it('compares the project core with the core that the CLI resolves', () => { + writeCore(projectCore, '@voidzero-dev/vite-plus-core', '0.0.0-any'); + expect(resolveCore('', project, cliModule)).toBe(join(bundled, 'index.js')); + }); + + it('rejects a stale project core', () => { + writeCore(projectCore, '@voidzero-dev/vite-plus-core', '0.0.0-stale'); + expect(() => resolveCore('', project, cliModule)).toThrow( + 'Expected @voidzero-dev/vite-plus-core@0.0.0-any, but found @voidzero-dev/vite-plus-core@0.0.0-stale', + ); + }); + + it('rejects upstream Vite in the CLI dependency', () => { + writeCore(bundled, 'vite', '8.2.2'); + expect(() => resolveCore('', project, cliModule)).toThrow( + 'Expected @voidzero-dev/vite-plus-core, but found vite@8.2.2', + ); + }); + }); + it('does not fall back to the project when the CLI dependency is missing', () => { writeCore(projectCore); rmSync(bundled, { recursive: true }); diff --git a/packages/cli/src/migration/__tests__/vite-peer-dependency-rule.spec.ts b/packages/cli/src/migration/__tests__/vite-peer-dependency-rule.spec.ts new file mode 100644 index 0000000000..cf35000c8c --- /dev/null +++ b/packages/cli/src/migration/__tests__/vite-peer-dependency-rule.spec.ts @@ -0,0 +1,275 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { parse as parseYaml } from 'yaml'; + +import { PackageManager, type WorkspaceInfo } from '../../types/index.js'; +import { VITE_PLUS_OVERRIDE_PACKAGES } from '../../utils/constants.js'; +import { createMigrationReport } from '../report.js'; + +// Keep the vite-plus spec stable; each test selects the core alias it needs. +vi.mock('../../utils/constants.js', async (importOriginal) => { + const mod = await importOriginal(); + return { + ...mod, + VITE_PLUS_VERSION: 'latest', + VITE_PLUS_OVERRIDE_PACKAGES: { ...mod.VITE_PLUS_OVERRIDE_PACKAGES }, + }; +}); + +const { + detectVitePlusBootstrapPending, + ensureVitePlusBootstrap, + rewriteStandaloneProject, + vitePeerDependencyRuleRequired, +} = await import('../migrator.js'); + +const STABLE_CORE = 'npm:@voidzero-dev/vite-plus-core@8.3.500'; +const PREVIEW_CORE = 'npm:@voidzero-dev/vite-plus-core@0.0.0-commit.0c515e3'; + +type PeerDependencyRules = { allowAny?: string[]; allowedVersions?: Record }; + +function makeWorkspaceInfo(rootDir: string, version = '10.33.0'): WorkspaceInfo { + return { + rootDir, + isMonorepo: false, + monorepoScope: '', + workspacePatterns: [], + parentDirs: [], + packageManager: PackageManager.pnpm, + packageManagerVersion: version, + downloadPackageManager: { + name: PackageManager.pnpm, + installDir: '/tmp', + binPrefix: '/tmp/bin', + packageName: PackageManager.pnpm, + version, + }, + packages: [], + }; +} + +function readJson(filePath: string): Record { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); +} + +function readWorkspaceRules(projectPath: string): PeerDependencyRules | undefined { + const workspace = parseYaml( + fs.readFileSync(path.join(projectPath, 'pnpm-workspace.yaml'), 'utf8'), + ) as { peerDependencyRules?: PeerDependencyRules }; + return workspace.peerDependencyRules; +} + +function readPackageJsonRules(projectPath: string): PeerDependencyRules | undefined { + const pkg = readJson(path.join(projectPath, 'package.json')) as { + pnpm?: { peerDependencyRules?: PeerDependencyRules }; + }; + return pkg.pnpm?.peerDependencyRules; +} + +function writeVitePlusProject(projectPath: string, peerDependencyRules: string[]) { + fs.writeFileSync( + path.join(projectPath, 'package.json'), + JSON.stringify({ + name: 'test', + devDependencies: { 'vite-plus': 'catalog:' }, + devEngines: { + packageManager: { name: 'pnpm', version: '10.33.0', onFail: 'download' }, + }, + }), + ); + fs.writeFileSync( + path.join(projectPath, 'pnpm-workspace.yaml'), + [ + 'catalog:', + ` vite: ${VITE_PLUS_OVERRIDE_PACKAGES.vite}`, + ' vite-plus: latest', + 'overrides:', + " vite@*: 'catalog:'", + ...peerDependencyRules, + '', + ].join('\n'), + ); +} + +describe('vitePeerDependencyRuleRequired', () => { + it.each([ + [STABLE_CORE, false], + ['npm:@voidzero-dev/vite-plus-core@9.0.0', false], + ['npm:@voidzero-dev/vite-plus-core@8.4.0-vp.0', true], + ['npm:@voidzero-dev/vite-plus-core@9.0.0-beta.3.vp.0', true], + ['npm:@voidzero-dev/vite-plus-core@0.0.0', true], + [PREVIEW_CORE, true], + ['npm:@voidzero-dev/vite-plus-core@1.4.0', true], + ['npm:@voidzero-dev/vite-plus-core@8.3.500+build.1', true], + ['npm:@voidzero-dev/vite-plus-core@latest', true], + ['file:../voidzero-dev-vite-plus-core-8.3.599.tgz', true], + ['https://pkg.pr.new/voidzero-dev/vite-plus/@voidzero-dev/vite-plus-core@1891', true], + ])('%s requires the rule: %s', (spec, required) => { + expect(vitePeerDependencyRuleRequired(spec)).toBe(required); + }); +}); + +describe('pnpm vite peer rule', () => { + let tmpDir: string; + const savedViteOverride = VITE_PLUS_OVERRIDE_PACKAGES.vite; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vp-vite-peer-rule-')); + }); + + afterEach(() => { + VITE_PLUS_OVERRIDE_PACKAGES.vite = savedViteOverride; + fs.rmSync(tmpDir, { recursive: true, force: true }); + }); + + describe('with a stable core version', () => { + beforeEach(() => { + VITE_PLUS_OVERRIDE_PACKAGES.vite = STABLE_CORE; + }); + + it('removes the vite rule from pnpm-workspace.yaml and keeps other entries', () => { + writeVitePlusProject(tmpDir, [ + 'peerDependencyRules:', + ' allowAny:', + ' - react', + ' - vite', + ' allowedVersions:', + " react: '*'", + " vite: '*'", + ]); + const report = createMigrationReport(); + + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(true); + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir), report); + + expect(readWorkspaceRules(tmpDir)).toEqual({ + allowAny: ['react'], + allowedVersions: { react: '*' }, + }); + expect(report.vitePeerDependencyRuleRemoved).toBe(true); + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + expect(ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir)).changed).toBe(false); + }); + + it('deletes peerDependencyRules from pnpm-workspace.yaml when no rule remains', () => { + writeVitePlusProject(tmpDir, [ + 'peerDependencyRules:', + ' allowAny: [vite, vitest]', + ' allowedVersions:', + " vite: '*'", + " vitest: '*'", + ]); + const report = createMigrationReport(); + + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir), report); + + expect(readWorkspaceRules(tmpDir)).toBeUndefined(); + expect(report.vitePeerDependencyRuleRemoved).toBe(true); + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + }); + + it('writes no peer rule for a project without one', () => { + writeVitePlusProject(tmpDir, []); + const report = createMigrationReport(); + + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir), report); + + expect(readWorkspaceRules(tmpDir)).toBeUndefined(); + expect(report.vitePeerDependencyRuleRemoved).toBe(false); + }); + + it('removes the vite rule from package.json before pnpm 10.6.2', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'test', + devDependencies: { 'vite-plus': 'latest' }, + pnpm: { + overrides: { react: '18.3.1' }, + peerDependencyRules: { + allowAny: ['react', 'vite'], + allowedVersions: { vite: '*' }, + }, + }, + }), + ); + const report = createMigrationReport(); + + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir, '10.6.1'), report); + + expect(readPackageJsonRules(tmpDir)).toEqual({ allowAny: ['react'] }); + expect(report.vitePeerDependencyRuleRemoved).toBe(true); + }); + + it('deletes package.json peerDependencyRules when no rule remains', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'test', + devDependencies: { 'vite-plus': 'latest' }, + pnpm: { + peerDependencyRules: { allowAny: ['vite'], allowedVersions: { vite: '*' } }, + }, + }), + ); + + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir, '10.6.1')); + + const pkg = readJson(path.join(tmpDir, 'package.json')) as { + pnpm: Record; + }; + expect(pkg.pnpm.peerDependencyRules).toBeUndefined(); + expect(pkg.pnpm.overrides).toEqual({ 'vite@*': STABLE_CORE }); + }); + + it('removes a vite rule during the full migration', () => { + fs.writeFileSync( + path.join(tmpDir, 'package.json'), + JSON.stringify({ + name: 'app', + devDependencies: { vite: '^7.0.0' }, + pnpm: { + peerDependencyRules: { + allowAny: ['react', 'vite'], + allowedVersions: { react: '*', vite: '*' }, + }, + }, + }), + ); + const report = createMigrationReport(); + + rewriteStandaloneProject(tmpDir, makeWorkspaceInfo(tmpDir, '10.6.1'), true, true, report); + + expect(readPackageJsonRules(tmpDir)).toEqual({ + allowAny: ['react'], + allowedVersions: { react: '*' }, + }); + expect(report.vitePeerDependencyRuleRemoved).toBe(true); + }); + }); + + describe('with a preview core version', () => { + beforeEach(() => { + VITE_PLUS_OVERRIDE_PACKAGES.vite = PREVIEW_CORE; + }); + + it('keeps writing the vite rule', () => { + writeVitePlusProject(tmpDir, []); + const report = createMigrationReport(); + + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(true); + ensureVitePlusBootstrap(makeWorkspaceInfo(tmpDir), report); + + expect(readWorkspaceRules(tmpDir)).toEqual({ + allowAny: ['vite'], + allowedVersions: { vite: '*' }, + }); + expect(report.vitePeerDependencyRuleRemoved).toBe(false); + expect(detectVitePlusBootstrapPending(tmpDir, PackageManager.pnpm)).toBe(false); + }); + }); +}); diff --git a/packages/cli/src/migration/bin.ts b/packages/cli/src/migration/bin.ts index de19f1893e..cd3828f51b 100644 --- a/packages/cli/src/migration/bin.ts +++ b/packages/cli/src/migration/bin.ts @@ -634,6 +634,11 @@ function showMigrationSummary(options: { if (report.packageManagerBootstrapConfigured) { log(`${styleText('gray', '•')} Package manager settings configured`); } + if (report.vitePeerDependencyRuleRemoved) { + log( + `${styleText('gray', '•')} Removed \`vite\` from pnpm peerDependencyRules: the core version now matches the bundled Vite`, + ); + } if (suggestFullMigration) { log(FULL_MIGRATION_HINT); } diff --git a/packages/cli/src/migration/migrator/catalog.ts b/packages/cli/src/migration/migrator/catalog.ts index cd6b13e998..8401e9e0b5 100644 --- a/packages/cli/src/migration/migrator/catalog.ts +++ b/packages/cli/src/migration/migrator/catalog.ts @@ -23,14 +23,18 @@ import { isAlignableVitestEcosystemPackage, isLegacyWrapperSpec, managedOverridePackages, + managedPeerDependencyRuleKeys, + mergeManagedPnpmPeerDependencyRules, + peerDependencyRulesHaveKey, pruneLegacyWrapperAliases, removeManagedVitestEntry, - removeVitestPeerDependencyRule, removeYamlMapVitestEntry, rewriteMonorepoProject, shouldDropProviderOverrideKey, + stalePeerDependencyRuleKeys, workspaceUsesWebdriverioProvider, } from '../migrator.ts'; +import { type MigrationReport } from '../report.ts'; import { type PreparedOxlintConfigs, LEGACY_WRAPPER_FALLBACK_VERSIONS, @@ -39,6 +43,8 @@ import { VITEST_IS_MANAGED_OVERRIDE, isPlainRecord, pnpmOverrideKey, + readPackageJsonIfExists, + vitePeerDependencyRuleRequired, type CatalogDependencyResolver, type PackageJsonDependencyField, type PnpmPackageJsonSettings, @@ -369,17 +375,17 @@ export function rewritePnpmWorkspaceYaml( allowAny.add(scalarString(allowAnyNode)); } } - // Common case: drop any lingering managed `vitest` allowAny entry. - if (!usesVitest && VITEST_IS_MANAGED_OVERRIDE) { - allowAny.items = allowAny.items.filter((n) => n.value !== 'vitest'); - } + // Drop lingering managed `vitest` and stale `vite` entries. + const stalePeerRuleKeys = stalePeerDependencyRuleKeys(usesVitest); + allowAny.items = allowAny.items.filter((n) => !stalePeerRuleKeys.includes(n.value)); + const peerRuleKeys = managedPeerDependencyRuleKeys(usesVitest); const existing = new Set(allowAny.items.map((n) => n.value)); - for (const key of Object.keys(managedOverridePackages(usesVitest))) { + for (const key of peerRuleKeys) { if (!existing.has(key)) { allowAny.add(scalarString(key)); } } - doc.setIn(['peerDependencyRules', 'allowAny'], allowAny); + setPeerDependencyRulesField(doc, 'allowAny', allowAny); // peerDependencyRules.allowedVersions // Same guard as above: a malformed non-map `allowedVersions:` value (pnpm @@ -391,15 +397,14 @@ export function rewritePnpmWorkspaceYaml( } else { allowedVersions = new YAMLMap, Scalar>(); } - // Common case: drop any lingering managed `vitest` allowedVersions entry. - if (!usesVitest) { - removeYamlMapVitestEntry(allowedVersions); + for (const key of stalePeerRuleKeys) { + allowedVersions.delete(key); } - for (const key of Object.keys(managedOverridePackages(usesVitest))) { + for (const key of peerRuleKeys) { // - vite: '*' allowedVersions.set(scalarString(key), scalarString('*')); } - doc.setIn(['peerDependencyRules', 'allowedVersions'], allowedVersions); + setPeerDependencyRulesField(doc, 'allowedVersions', allowedVersions); // minimumReleaseAgeExclude: exempt the Vite+-managed packages (vite-plus, // @voidzero-dev/*, the ox* family, and the vitest family) from the age gate. @@ -1215,7 +1220,6 @@ export function rewriteRootWorkspacePackageJson( // to a `catalog:` reference. See https://github.com/oven-sh/bun/issues/8406. setDirectViteEdge(pkg, true, catalogDependencyResolver); } else if (packageManager === PackageManager.pnpm) { - const overrideKeys = Object.keys(managedOverridePackages(workspaceUsesVitest)); const usePnpmWorkspaceSettings = pnpmSupportsWorkspaceSettings(pnpmVersion ?? ''); if (!usePnpmWorkspaceSettings) { // Strip selector-shaped overrides (e.g. `parent>@vitest/browser-playwright`) @@ -1223,27 +1227,20 @@ export function rewriteRootWorkspacePackageJson( // overrides into the new pnpm config. dropRemovePackageOverrideKeys(pkg.pnpm?.overrides); // Common case: drop a lingering managed `vitest` override before merging. + // `mergeManagedPnpmPeerDependencyRules` drops its peer rule. if (!workspaceUsesVitest) { removeManagedVitestEntry(pkg.pnpm?.overrides, 'pnpm-ranged'); } - if (!workspaceUsesVitest && pkg.pnpm?.peerDependencyRules) { - removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); - } pkg.pnpm = { ...pkg.pnpm, overrides: mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), - peerDependencyRules: { - ...pkg.pnpm?.peerDependencyRules, - allowAny: [ - ...new Set([...(pkg.pnpm?.peerDependencyRules?.allowAny ?? []), ...overrideKeys]), - ], - allowedVersions: { - ...pkg.pnpm?.peerDependencyRules?.allowedVersions, - ...Object.fromEntries(overrideKeys.map((key) => [key, '*'])), - }, - }, + peerDependencyRules: mergeManagedPnpmPeerDependencyRules( + pkg.pnpm?.peerDependencyRules, + workspaceUsesVitest, + ), }; } else { + const overrideKeys = Object.keys(managedOverridePackages(workspaceUsesVitest)); for (const key of [...overrideKeys, ...PROVIDER_OVERRIDE_DROP_NAMES]) { if (pkg.resolutions?.[key]) { delete pkg.resolutions[key]; @@ -1349,6 +1346,26 @@ export function pnpmWorkspaceMinimumReleaseAgeExemptionsPending(projectPath: str return PNPM_MINIMUM_RELEASE_AGE_EXCLUDES.some((exclude) => !existing.has(exclude)); } +// Write one pnpm-workspace.yaml `peerDependencyRules` field, or delete it when +// no entry remains. An emptied `peerDependencyRules` map is deleted too. +function setPeerDependencyRulesField( + doc: YamlDocument, + field: 'allowAny' | 'allowedVersions', + node: YAMLSeq | YAMLMap, +): void { + if (node.items.length > 0) { + doc.setIn(['peerDependencyRules', field], node); + return; + } + if (doc.hasIn(['peerDependencyRules', field])) { + doc.deleteIn(['peerDependencyRules', field]); + } + const rules = doc.get('peerDependencyRules'); + if (rules instanceof YAMLMap && rules.items.length === 0) { + doc.delete('peerDependencyRules'); + } +} + export function readPnpmWorkspacePeerDependencyRules( projectPath: string, ): { allowAny?: string[]; allowedVersions?: Record } | undefined { @@ -1362,6 +1379,41 @@ export function readPnpmWorkspacePeerDependencyRules( return doc?.peerDependencyRules; } +// Whether the root pnpm config (the package.json `pnpm` field or +// pnpm-workspace.yaml) holds a `vite` peer rule. +export function hasVitePeerDependencyRule(projectPath: string): boolean { + if (peerDependencyRulesHaveKey(readPnpmWorkspacePeerDependencyRules(projectPath), ['vite'])) { + return true; + } + const pkg = readPackageJsonIfExists(path.join(projectPath, 'package.json')) as + | { pnpm?: PnpmPackageJsonSettings } + | undefined; + return peerDependencyRulesHaveKey(pkg?.pnpm?.peerDependencyRules, ['vite']); +} + +// Capture the `vite` peer rule before a migration step. Call the returned +// function after the step: it records the rule's removal in the report, so the +// migrate summary names it (see `vitePeerDependencyRuleRequired`). +export function trackVitePeerDependencyRuleRemoval( + projectPath: string, + packageManager: PackageManager, + report: MigrationReport | undefined, +): () => void { + if ( + !report || + packageManager !== PackageManager.pnpm || + vitePeerDependencyRuleRequired() || + !hasVitePeerDependencyRule(projectPath) + ) { + return () => {}; + } + return () => { + if (!hasVitePeerDependencyRule(projectPath)) { + report.vitePeerDependencyRuleRemoved = true; + } + }; +} + export function ensurePnpmWorkspacePackages( projectPath: string, workspacePatterns: string[], diff --git a/packages/cli/src/migration/migrator/orchestrators.ts b/packages/cli/src/migration/migrator/orchestrators.ts index dc4a2c5550..7147aed0ad 100644 --- a/packages/cli/src/migration/migrator/orchestrators.ts +++ b/packages/cli/src/migration/migrator/orchestrators.ts @@ -25,6 +25,7 @@ import { injectLintTypeCheckDefaults, managedOverridePackages, mergeManagedPnpmOverrides, + mergeManagedPnpmPeerDependencyRules, mergeStagedConfigToViteConfig, mergeTsdownConfigFile, mergeViteConfigFiles, @@ -40,7 +41,6 @@ import { removeLintStagedFromPackageJson, removeMigratedOxlintConfigs, removeManagedVitestEntry, - removeVitestPeerDependencyRule, rewriteAllImports, rewriteBunCatalog, rewriteLintStagedConfigFile, @@ -52,6 +52,7 @@ import { setDirectViteEdge, sourceTreeReferencesRetainedVitestModule, takePnpmWorkspaceSettings, + trackVitePeerDependencyRuleRemoval, usesVitestBrowserMode, usesWebdriverioProvider, workspaceUsesVitestDirectly, @@ -81,6 +82,11 @@ export function rewriteStandaloneProject( } const packageManager = workspaceInfo.packageManager; + const reportVitePeerDependencyRuleRemoval = trackVitePeerDependencyRuleRemoval( + projectPath, + packageManager, + report, + ); const catalogDependencyResolver = createCatalogDependencyResolver(projectPath, packageManager); const vitestEcosystemPackages = collectVitestEcosystemInstallDependencyNames(projectPath); // Captured before `rewritePackageJson` strips `oxlint`; the import rewriter @@ -193,13 +199,10 @@ export function rewriteStandaloneProject( // whose target is a removed package, before re-merging the user's // overrides into the new pnpm config. dropRemovePackageOverrideKeys(pkg.pnpm?.overrides); - // Common case: drop a lingering managed `vitest` override + its peer - // rules before re-merging. + // Common case: drop a lingering managed `vitest` override before + // re-merging. `mergeManagedPnpmPeerDependencyRules` drops its peer rule. if (!usesVitest) { removeManagedVitestEntry(pkg.pnpm?.overrides, 'pnpm-ranged'); - if (pkg.pnpm?.peerDependencyRules) { - removeVitestPeerDependencyRule(pkg.pnpm.peerDependencyRules); - } } // Project already has pnpm config in package.json -- keep using it. // `mergeManagedPnpmOverrides` writes the range-qualified keys and drops @@ -208,16 +211,10 @@ export function rewriteStandaloneProject( pkg.pnpm = { ...pkg.pnpm, overrides: mergeManagedPnpmOverrides(pkg.pnpm?.overrides, managed), - peerDependencyRules: { - ...pkg.pnpm?.peerDependencyRules, - allowAny: [ - ...new Set([...(pkg.pnpm?.peerDependencyRules?.allowAny ?? []), ...overrideKeys]), - ], - allowedVersions: { - ...pkg.pnpm?.peerDependencyRules?.allowedVersions, - ...Object.fromEntries(overrideKeys.map((key) => [key, '*'])), - }, - }, + peerDependencyRules: mergeManagedPnpmPeerDependencyRules( + pkg.pnpm?.peerDependencyRules, + usesVitest, + ), }; } else { movedPnpmSettings = takePnpmWorkspaceSettings(pkg); @@ -345,6 +342,7 @@ export function rewriteStandaloneProject( dropDeadOxlintPluginsDependency(projectPath, workspaceInfo.packages, originalOxlintDependencies); wrapLazyPluginsInViteConfig(projectPath, silent, report); migrateTaskCacheConfigInViteConfig(projectPath, silent, report); + reportVitePeerDependencyRuleRemoval(); } /** @@ -357,6 +355,11 @@ export function rewriteMonorepo( silent = false, report?: MigrationReport, ): void { + const reportVitePeerDependencyRuleRemoval = trackVitePeerDependencyRuleRemoval( + workspaceInfo.rootDir, + workspaceInfo.packageManager, + report, + ); const catalogDependencyResolver = createCatalogDependencyResolver( workspaceInfo.rootDir, workspaceInfo.packageManager, @@ -515,6 +518,7 @@ export function rewriteMonorepo( wrapLazyPluginsInViteConfig(projectPath, silent, report); migrateTaskCacheConfigInViteConfig(projectPath, silent, report); } + reportVitePeerDependencyRuleRemoval(); } /** diff --git a/packages/cli/src/migration/migrator/shared.ts b/packages/cli/src/migration/migrator/shared.ts index 03473942b6..17ba284ad7 100644 --- a/packages/cli/src/migration/migrator/shared.ts +++ b/packages/cli/src/migration/migrator/shared.ts @@ -3,9 +3,13 @@ import path from 'node:path'; import * as prompts from '@voidzero-dev/vite-plus-prompts'; import type { OxlintConfig } from 'oxlint'; -import { coerce, satisfies } from 'verkit'; +import { coerce, satisfies, tryParse } from 'verkit'; -import { VITEST_VERSION, VITE_PLUS_OVERRIDE_PACKAGES } from '../../utils/constants.ts'; +import { + VITEST_VERSION, + VITE_PLUS_CORE_ALIAS_PREFIX, + VITE_PLUS_OVERRIDE_PACKAGES, +} from '../../utils/constants.ts'; import { readJsonFile } from '../../utils/json.ts'; import { detectPackageMetadata } from '../../utils/package.ts'; import { displayRelative } from '../../utils/path.ts'; @@ -211,6 +215,33 @@ export const VITEST_BROWSER_DEP_NAMES = [ // and must be left untouched. export const VITEST_IS_MANAGED_OVERRIDE = 'vitest' in VITE_PLUS_OVERRIDE_PACKAGES; +/** + * Whether pnpm still needs the managed `vite` peer rule (`allowAny: [vite]`, + * `allowedVersions: { vite: '*' }`) for the given core alias. + * + * A stable core version encodes the bundled Vite version (`8.3.500` bundles + * Vite `8.3.5`, see rfcs/core-version-alignment.md). Package managers check + * `vite` peer ranges against it correctly, so the rule would only hide real + * incompatibilities. Every other spec still needs the rule: a preview + * (`0.0.0-commit.`), a Vite+ prerelease (`8.4.0-vp.0` fails `^8.0.0`), a + * `1.x` core from before the alignment, a dist-tag, or a `file:` or URL spec + * whose version is unknown. + */ +export function vitePeerDependencyRuleRequired( + viteSpec: string | undefined = VITE_PLUS_OVERRIDE_PACKAGES.vite, +): boolean { + if (!viteSpec?.startsWith(VITE_PLUS_CORE_ALIAS_PREFIX)) { + return true; + } + const version = tryParse(viteSpec.slice(VITE_PLUS_CORE_ALIAS_PREFIX.length)); + return ( + !version || + version.major < 8 || + (version.prerelease?.length ?? 0) > 0 || + (version.build?.length ?? 0) > 0 + ); +} + // Fallback specs used when normalizing a stale wrapper alias. Real user // ranges (e.g. `vitest: ^3.0.0`) are preserved — only the wrapper alias is // rewritten. For `vitest`, we substitute the vitest version vite-plus @@ -334,7 +365,7 @@ function checkPackageVersion(projectPath: string, name: string, minVersion: stri return true; } -type PnpmPeerDependencyRules = { +export type PnpmPeerDependencyRules = { allowAny?: string[]; allowedVersions?: Record; [key: string]: unknown; diff --git a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts index 5a4105b168..51f07e7bb4 100644 --- a/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts +++ b/packages/cli/src/migration/migrator/vite-plus-bootstrap.ts @@ -27,6 +27,9 @@ import { isLegacyWrapperSpec, isProtocolPinnedSpec, managedOverridePackages, + managedPeerDependencyRuleKeys, + mergeManagedPnpmPeerDependencyRules, + peerDependencyRulesHaveKey, migratePnpmSettingsToWorkspaceYaml, normalizeVitestPeerCatalogSpec, pnpmPackageJsonSettingsPending, @@ -44,7 +47,9 @@ import { rewritePnpmWorkspaceYaml, rewriteYarnrcYml, setDirectViteEdge, + stalePeerDependencyRuleKeys, takePnpmWorkspaceSettings, + trackVitePeerDependencyRuleRemoval, vitestEcosystemCatalogReferencesPending, workspaceUsesVitestDirectly, workspaceUsesWebdriverio, @@ -231,18 +236,14 @@ function pnpmPeerDependencyRulesSatisfyVitePlus( | undefined, usesVitest: boolean, ): boolean { - const allowAny = new Set(peerDependencyRules?.allowAny ?? []); - const allowedVersions = peerDependencyRules?.allowedVersions ?? {}; - // Common case: a lingering managed `vitest` peer rule is NOT satisfied. - if ( - !usesVitest && - VITEST_IS_MANAGED_OVERRIDE && - (allowAny.has('vitest') || allowedVersions.vitest !== undefined) - ) { + // A lingering managed `vitest` rule or a stale `vite` rule is NOT satisfied. + if (peerDependencyRulesHaveKey(peerDependencyRules, stalePeerDependencyRuleKeys(usesVitest))) { return false; } - const overrideKeys = Object.keys(managedOverridePackages(usesVitest)); - return overrideKeys.every((key) => allowAny.has(key) && allowedVersions[key] === '*'); + const allowAny = new Set(peerDependencyRules?.allowAny ?? []); + const allowedVersions = peerDependencyRules?.allowedVersions ?? {}; + const ruleKeys = managedPeerDependencyRuleKeys(usesVitest); + return ruleKeys.every((key) => allowAny.has(key) && allowedVersions[key] === '*'); } function npmVitePlusManagedDependenciesPending( @@ -921,34 +922,19 @@ function ensureOverrideEntries( } function ensurePnpmPeerDependencyRules(pkg: BootstrapPackageJson, usesVitest: boolean): boolean { - const overrideKeys = Object.keys(managedOverridePackages(usesVitest)); pkg.pnpm ??= {}; - // Common case: drop a lingering managed `vitest` peer rule from the source - // shape before re-deriving the managed rules. - const seed = { ...pkg.pnpm.peerDependencyRules } as { - allowAny?: string[]; - allowedVersions?: Record; - }; - if (!usesVitest && VITEST_IS_MANAGED_OVERRIDE) { - if (Array.isArray(seed.allowAny)) { - seed.allowAny = seed.allowAny.filter((key) => key !== 'vitest'); - } - if (seed.allowedVersions) { - seed.allowedVersions = { ...seed.allowedVersions }; - delete seed.allowedVersions.vitest; - } - } - const peerDependencyRules = { - ...seed, - allowAny: [...new Set([...(seed.allowAny ?? []), ...overrideKeys])], - allowedVersions: { - ...seed.allowedVersions, - ...Object.fromEntries(overrideKeys.map((key) => [key, '*'])), - }, - }; + const peerDependencyRules = mergeManagedPnpmPeerDependencyRules( + pkg.pnpm.peerDependencyRules, + usesVitest, + ); const changed = - JSON.stringify(pkg.pnpm.peerDependencyRules ?? {}) !== JSON.stringify(peerDependencyRules); - pkg.pnpm.peerDependencyRules = peerDependencyRules; + JSON.stringify(pkg.pnpm.peerDependencyRules ?? {}) !== + JSON.stringify(peerDependencyRules ?? {}); + if (peerDependencyRules) { + pkg.pnpm.peerDependencyRules = peerDependencyRules; + } else { + delete pkg.pnpm.peerDependencyRules; + } return changed; } @@ -967,6 +953,11 @@ export function ensureVitePlusBootstrap( if (!fs.existsSync(packageJsonPath)) { return result; } + const reportVitePeerDependencyRuleRemoval = trackVitePeerDependencyRuleRemoval( + projectPath, + workspaceInfo.packageManager, + report, + ); // Shared override/catalog sinks are workspace-wide, so keep vitest managed // when any package needs it. Each package's direct vitest dependency is @@ -1276,6 +1267,7 @@ export function ensureVitePlusBootstrap( if (result.changed && report) { report.packageManagerBootstrapConfigured = true; } + reportVitePeerDependencyRuleRemoval(); return result; } diff --git a/packages/cli/src/migration/migrator/vitest-ecosystem.ts b/packages/cli/src/migration/migrator/vitest-ecosystem.ts index ffff16ac75..35824336a7 100644 --- a/packages/cli/src/migration/migrator/vitest-ecosystem.ts +++ b/packages/cli/src/migration/migrator/vitest-ecosystem.ts @@ -27,10 +27,13 @@ import { REMOVE_PACKAGES, VITEST_BROWSER_DEP_NAMES, VITEST_IS_MANAGED_OVERRIDE, + isPlainRecord, pnpmOverrideKey, + vitePeerDependencyRuleRequired, type CatalogDependencyResolver, type ManagedOverrideKeyStyle, type PackageJsonDependencyField, + type PnpmPeerDependencyRules, } from './shared.ts'; // Official packages that do not declare a required `vitest` peer. Keep them @@ -538,23 +541,74 @@ function managedVitestOverrideKeys(keyStyle: ManagedOverrideKeyStyle): string[] return keyStyle === 'pnpm-ranged' ? ['vitest', pnpmOverrideKey('vitest')] : ['vitest']; } -// Remove the managed `vitest` entry from pnpm peerDependencyRules (its -// `allowAny` array entry and `allowedVersions.vitest`), in place. Works on both -// the package.json `pnpm.peerDependencyRules` JSON shape and the same shape read -// back from pnpm-workspace.yaml. -export function removeVitestPeerDependencyRule(peerDependencyRules: { - allowAny?: string[]; - allowedVersions?: Record; -}): void { - if (!VITEST_IS_MANAGED_OVERRIDE) { - return; +// The pnpm peerDependencyRules keys that migration removes: +// - `vitest`, a lingering managed rule, when the workspace does not use Vitest. +// - `vite`, once its core alias satisfies `vite` peer ranges (see +// `vitePeerDependencyRuleRequired`). Then the rule only hides real +// incompatibilities. Migration cannot tell whether an earlier migration or the +// user wrote the entry; its only purpose was to accept the `1.x` alias, so +// both go. +export function stalePeerDependencyRuleKeys(usesVitest: boolean): string[] { + const keys: string[] = []; + if (!usesVitest && VITEST_IS_MANAGED_OVERRIDE) { + keys.push('vitest'); } - if (Array.isArray(peerDependencyRules.allowAny)) { - peerDependencyRules.allowAny = peerDependencyRules.allowAny.filter((key) => key !== 'vitest'); + if (!vitePeerDependencyRuleRequired()) { + keys.push('vite'); + } + return keys; +} + +// Whether pnpm peerDependencyRules hold an `allowAny` or `allowedVersions` entry +// for one of `keys`. Works on both the package.json `pnpm.peerDependencyRules` +// JSON shape and the same shape read back from pnpm-workspace.yaml. +export function peerDependencyRulesHaveKey( + rules: { allowAny?: unknown; allowedVersions?: unknown } | null | undefined, + keys: readonly string[], +): boolean { + return keys.some( + (key) => + (Array.isArray(rules?.allowAny) && rules.allowAny.includes(key)) || + (isPlainRecord(rules?.allowedVersions) && rules.allowedVersions[key] !== undefined), + ); +} + +// The pnpm peerDependencyRules keys vite-plus manages: the managed override +// keys, minus `vite` once its core alias satisfies `vite` peer ranges. +export function managedPeerDependencyRuleKeys(usesVitest: boolean): string[] { + const keys = Object.keys(managedOverridePackages(usesVitest)); + return vitePeerDependencyRuleRequired() ? keys : keys.filter((key) => key !== 'vite'); +} + +// Re-derive the managed pnpm peerDependencyRules on top of the package.json +// `pnpm.peerDependencyRules` shape. Returns the new rules, or `undefined` when +// no rule remains so the caller can drop the field. Does not mutate `rules`. +export function mergeManagedPnpmPeerDependencyRules( + rules: PnpmPeerDependencyRules | undefined, + usesVitest: boolean, +): PnpmPeerDependencyRules | undefined { + const stale = new Set(stalePeerDependencyRuleKeys(usesVitest)); + const keys = managedPeerDependencyRuleKeys(usesVitest); + const allowAny = [ + ...new Set([ + ...(Array.isArray(rules?.allowAny) ? rules.allowAny : []).filter((key) => !stale.has(key)), + ...keys, + ]), + ]; + const allowedVersions = { + ...Object.fromEntries( + Object.entries(rules?.allowedVersions ?? {}).filter(([key]) => !stale.has(key)), + ), + ...Object.fromEntries(keys.map((key) => [key, '*'])), + }; + const next: PnpmPeerDependencyRules = { ...rules, allowAny, allowedVersions }; + if (allowAny.length === 0) { + delete next.allowAny; } - if (peerDependencyRules.allowedVersions) { - delete peerDependencyRules.allowedVersions.vitest; + if (Object.keys(allowedVersions).length === 0) { + delete next.allowedVersions; } + return Object.keys(next).length > 0 ? next : undefined; } // Legacy wrapper package names that may appear as the target of override diff --git a/packages/cli/src/migration/report.ts b/packages/cli/src/migration/report.ts index ab9d75722f..220d5f83a3 100644 --- a/packages/cli/src/migration/report.ts +++ b/packages/cli/src/migration/report.ts @@ -33,6 +33,7 @@ export interface MigrationReport { gitHooksConfigured: boolean; frameworkShimAdded: boolean; packageManagerBootstrapConfigured: boolean; + vitePeerDependencyRuleRemoved: boolean; dependencyUpgrades: DependencyVersionChange[]; warnings: string[]; manualSteps: string[]; @@ -62,6 +63,7 @@ export function createMigrationReport(): MigrationReport { gitHooksConfigured: false, frameworkShimAdded: false, packageManagerBootstrapConfigured: false, + vitePeerDependencyRuleRemoved: false, dependencyUpgrades: [], warnings: [], manualSteps: [], diff --git a/packages/cli/src/resolve-core.ts b/packages/cli/src/resolve-core.ts index c1b9886445..92d20fcbed 100644 --- a/packages/cli/src/resolve-core.ts +++ b/packages/cli/src/resolve-core.ts @@ -2,27 +2,57 @@ import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { join } from 'node:path'; +import { VITE_PLUS_CORE_ALIAS_PREFIX, VITE_PLUS_CORE_NAME } from './utils/constants.ts'; import { readNearestPackageJson } from './utils/package.ts'; -const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core'; - -function checkCoreVersion(packageJsonPath: string, expectedVersion: string): void { +/** + * Check that a resolved `vite` is the core package, at `expectedVersion` when + * one is given. Returns the core version. + */ +function checkCoreVersion( + packageJsonPath: string, + expectedVersion: string | undefined, +): string | undefined { const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { name?: string; version?: string; }; - if (pkg.name !== CORE_PACKAGE_NAME || pkg.version !== expectedVersion) { + if ( + pkg.name !== VITE_PLUS_CORE_NAME || + (expectedVersion !== undefined && pkg.version !== expectedVersion) + ) { + const expected = + expectedVersion === undefined + ? VITE_PLUS_CORE_NAME + : `${VITE_PLUS_CORE_NAME}@${expectedVersion}`; throw new Error( - `Expected ${CORE_PACKAGE_NAME}@${expectedVersion}, but found ${pkg.name}@${pkg.version} at ${packageJsonPath}. ` + + `Expected ${expected}, but found ${pkg.name}@${pkg.version} at ${packageJsonPath}. ` + 'Run `vp migrate` to align the Vite alias, then run `vp install`.', ); } + return pkg.version; +} + +/** + * Read the core version that the selected CLI pins through its `vite` alias. + * The core version encodes the bundled Vite version, so it differs from the + * CLI version (rfcs/core-version-alignment.md). Packing turns the repository's + * `workspace:` spec into the exact alias. Any other spec pins no version. + */ +function readAliasCoreVersion(cliPackageJsonPath: string): string | undefined { + const { dependencies } = JSON.parse(readFileSync(cliPackageJsonPath, 'utf8')) as { + dependencies?: Record; + }; + const spec = dependencies?.vite; + return spec?.startsWith(VITE_PLUS_CORE_ALIAS_PREFIX) + ? spec.slice(VITE_PLUS_CORE_ALIAS_PREFIX.length) + : undefined; } function checkProjectCoreVersion( cwd: string, corePackageJsonPath: string, - expectedVersion: string, + expectedVersion: string | undefined, ): void { // npm can hoist an upstream Vite peer even when the project only declares // vite-plus. Validate Vite only when the nearest package declares it. @@ -58,19 +88,21 @@ export function resolveCore( modulePath = import.meta.url, ): string { const cliRequire = createRequire(modulePath); - // Read the selected CLI's installed manifest. A static JSON import is inlined - // during the build, before CI and preview packers can stamp a new version. - const { version: expectedVersion } = JSON.parse( - readFileSync(cliRequire.resolve('vite-plus/package.json'), 'utf8'), - ) as { version: string }; let corePackageJsonPath: string; try { corePackageJsonPath = cliRequire.resolve('vite/package.json'); } catch (cause) { throw new Error('Could not resolve the bundled Vite dependency. Run `vp install`.', { cause }); } - checkCoreVersion(corePackageJsonPath, expectedVersion); - checkProjectCoreVersion(cwd, corePackageJsonPath, expectedVersion); + // Read the selected CLI's installed manifest. A static JSON import is inlined + // during the build, before CI and preview packers can stamp a new version. + // The project's core must match the core that the CLI resolves, so a stale + // project core also fails when the CLI alias pins no version. + const coreVersion = checkCoreVersion( + corePackageJsonPath, + readAliasCoreVersion(cliRequire.resolve('vite-plus/package.json')), + ); + checkProjectCoreVersion(cwd, corePackageJsonPath, coreVersion); return cliRequire.resolve(`vite${subpath}`); } diff --git a/packages/cli/src/sync-versions/__tests__/plan.spec.ts b/packages/cli/src/sync-versions/__tests__/plan.spec.ts index dcb9c29956..8b4b4751b1 100644 --- a/packages/cli/src/sync-versions/__tests__/plan.spec.ts +++ b/packages/cli/src/sync-versions/__tests__/plan.spec.ts @@ -10,6 +10,7 @@ import { const toolchain: SyncVersionsToolchain = { vitePlus: '0.4.0', + vitePlusCore: '8.3.500', vitest: '5.0.0', }; @@ -50,7 +51,7 @@ describe('planSyncVersions', () => { '@vitest/coverage-v8': '5.0.0', '@vitest/eslint-plugin': '1.6.0', '@vitest/coverage-c8': '0.33.0', - '@voidzero-dev/vite-plus-core': '0.4.0', + '@voidzero-dev/vite-plus-core': '8.3.500', 'vite-plus': '0.4.0', vitest: '5.0.0', }, @@ -77,7 +78,7 @@ describe('planSyncVersions', () => { devDependencies: { '@vitest/ui': 'npm:@vitest/ui@5.0.0', 'vite-plus': 'npm:@scope/vite-plus-fork@0.3.0', - vite: 'npm:@voidzero-dev/vite-plus-core@0.4.0', + vite: 'npm:@voidzero-dev/vite-plus-core@8.3.500', vitest: 'npm:vitest@5.0.0', }, }); @@ -113,7 +114,7 @@ describe('planSyncVersions', () => { catalog: { '@vitest/coverage-v8': '5.0.0' }, catalogs: { toolchain: { - vite: 'npm:@voidzero-dev/vite-plus-core@0.4.0', + vite: 'npm:@voidzero-dev/vite-plus-core@8.3.500', 'vite-plus': '0.4.0', }, }, @@ -138,7 +139,7 @@ describe('planSyncVersions', () => { .replace("vitest: '^4.1.11'", "vitest: '5.0.0'") .replace( 'vite: "npm:@voidzero-dev/vite-plus-core@0.3.0"', - 'vite: "npm:@voidzero-dev/vite-plus-core@0.4.0"', + 'vite: "npm:@voidzero-dev/vite-plus-core@8.3.500"', ) .replace('vite-plus: 0.3.0', 'vite-plus: 0.4.0'), ); diff --git a/packages/cli/src/sync-versions/__tests__/protocol.spec.ts b/packages/cli/src/sync-versions/__tests__/protocol.spec.ts index a7120c3c11..b95c7e61ef 100644 --- a/packages/cli/src/sync-versions/__tests__/protocol.spec.ts +++ b/packages/cli/src/sync-versions/__tests__/protocol.spec.ts @@ -6,6 +6,7 @@ const manifest = { schemaVersion: 1, nodes: [ { id: 'vite-plus', version: '0.4.0' }, + { id: 'vite-plus-core', version: '8.3.500' }, { id: 'vitest', version: '5.0.0' }, ], }; @@ -49,9 +50,10 @@ describe('runSyncVersionsProtocol', () => { }); describe('toolchainFromManifest', () => { - it('reads the exact Vite+ and Vitest versions', () => { + it('reads the exact Vite+, core, and Vitest versions', () => { expect(toolchainFromManifest(manifest)).toEqual({ vitePlus: '0.4.0', + vitePlusCore: '8.3.500', vitest: '5.0.0', }); }); @@ -64,6 +66,14 @@ describe('toolchainFromManifest', () => { schemaVersion: 1, nodes: [ { id: 'vite-plus', version: '0.4.0' }, + { id: 'vitest', version: '5.0.0' }, + ], + }, + { + schemaVersion: 1, + nodes: [ + { id: 'vite-plus', version: '0.4.0' }, + { id: 'vite-plus-core', version: '8.3.500' }, { id: 'vitest', version: '' }, ], }, diff --git a/packages/cli/src/sync-versions/plan.ts b/packages/cli/src/sync-versions/plan.ts index 72258b163b..b87128598b 100644 --- a/packages/cli/src/sync-versions/plan.ts +++ b/packages/cli/src/sync-versions/plan.ts @@ -88,6 +88,8 @@ export type SyncVersionsManifestSnapshot = SyncVersionsRequestV1['manifests'][nu export interface SyncVersionsToolchain { vitePlus: string; + /** Encodes the bundled Vite version, so it differs from `vitePlus`. */ + vitePlusCore: string; vitest: string; } @@ -141,9 +143,12 @@ function parsePackageJson(contents: string): Record { } function targetVersion(name: string, toolchain: SyncVersionsToolchain): string | undefined { - if (name === 'vite-plus' || name === '@voidzero-dev/vite-plus-core') { + if (name === 'vite-plus') { return toolchain.vitePlus; } + if (name === '@voidzero-dev/vite-plus-core') { + return toolchain.vitePlusCore; + } if (name === 'vitest' || isAlignableVitestEcosystemPackage(name)) { return toolchain.vitest; } diff --git a/packages/cli/src/sync-versions/protocol.ts b/packages/cli/src/sync-versions/protocol.ts index f6cf1e78f8..d2b1f52357 100644 --- a/packages/cli/src/sync-versions/protocol.ts +++ b/packages/cli/src/sync-versions/protocol.ts @@ -35,6 +35,7 @@ export function toolchainFromManifest(input: unknown): SyncVersionsToolchain { const manifest = toolchainManifestSchema.parse(input); return { vitePlus: requiredToolVersion(manifest.nodes, 'vite-plus'), + vitePlusCore: requiredToolVersion(manifest.nodes, 'vite-plus-core'), vitest: requiredToolVersion(manifest.nodes, 'vitest'), }; } diff --git a/packages/cli/src/utils/__tests__/constants.spec.ts b/packages/cli/src/utils/__tests__/constants.spec.ts index 5a2b514ef1..2c4e4b4b1d 100644 --- a/packages/cli/src/utils/__tests__/constants.spec.ts +++ b/packages/cli/src/utils/__tests__/constants.spec.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; +import corePkg from '../../../../core/package.json' with { type: 'json' }; import cliPkg from '../../../package.json' with { type: 'json' }; describe('Vite+ dependency versions', () => { @@ -8,19 +9,50 @@ describe('Vite+ dependency versions', () => { vi.resetModules(); }); - it('uses the concrete CLI version for vite-plus and vite-plus-core by default', async () => { + it('uses the concrete CLI and core versions by default', async () => { vi.stubEnv('VP_VERSION', ''); + vi.stubEnv('VP_CORE_VERSION', ''); vi.stubEnv('VP_OVERRIDE_PACKAGES', ''); vi.resetModules(); - const { VITE_PLUS_OVERRIDE_PACKAGES, VITE_PLUS_VERSION } = await import('../constants.js'); + const { VITE_PLUS_CORE_VERSION, VITE_PLUS_OVERRIDE_PACKAGES, VITE_PLUS_VERSION } = + await import('../constants.js'); expect(VITE_PLUS_VERSION).toBe(cliPkg.version); + expect(VITE_PLUS_CORE_VERSION).toBe(corePkg.version); expect(VITE_PLUS_OVERRIDE_PACKAGES.vite).toBe( - `npm:@voidzero-dev/vite-plus-core@${cliPkg.version}`, + `npm:@voidzero-dev/vite-plus-core@${corePkg.version}`, ); }); + it.each(['1.0.1', '0.0.0', '0.0.0-commit.0c515e3'])( + 'keeps the core manifest version for VP_VERSION %s', + async (version) => { + vi.stubEnv('VP_VERSION', version); + vi.stubEnv('VP_CORE_VERSION', ''); + vi.stubEnv('VP_OVERRIDE_PACKAGES', ''); + vi.resetModules(); + + const { VITE_PLUS_CORE_VERSION } = await import('../constants.js'); + + expect(VITE_PLUS_CORE_VERSION).toBe(corePkg.version); + }, + ); + + it('uses VP_CORE_VERSION for the core alias', async () => { + vi.stubEnv('VP_VERSION', '0.0.0'); + vi.stubEnv('VP_CORE_VERSION', '8.3.599'); + vi.stubEnv('VP_OVERRIDE_PACKAGES', ''); + vi.resetModules(); + + const { VITE_PLUS_CORE_VERSION, VITE_PLUS_OVERRIDE_PACKAGES, VITE_PLUS_VERSION } = + await import('../constants.js'); + + expect(VITE_PLUS_VERSION).toBe('0.0.0'); + expect(VITE_PLUS_CORE_VERSION).toBe('8.3.599'); + expect(VITE_PLUS_OVERRIDE_PACKAGES.vite).toBe('npm:@voidzero-dev/vite-plus-core@8.3.599'); + }); + it('preserves explicit prerelease overrides', async () => { const vitePlusUrl = 'https://pkg.pr.new/voidzero-dev/vite-plus@1891'; const viteCoreUrl = diff --git a/packages/cli/src/utils/constants.ts b/packages/cli/src/utils/constants.ts index 6338fc0ea6..9c0191b224 100644 --- a/packages/cli/src/utils/constants.ts +++ b/packages/cli/src/utils/constants.ts @@ -1,9 +1,18 @@ import { createRequire } from 'node:module'; +import corePkg from '../../../core/package.json' with { type: 'json' }; import cliPkg from '../../package.json' with { type: 'json' }; export const VITE_PLUS_NAME = 'vite-plus'; export const VITE_PLUS_VERSION = process.env.VP_VERSION || cliPkg.version; +export const VITE_PLUS_CORE_NAME = '@voidzero-dev/vite-plus-core'; +// Projects and the CLI alias `vite` to the core: `vite: npm:@voidzero-dev/vite-plus-core@`. +export const VITE_PLUS_CORE_ALIAS_PREFIX = `npm:${VITE_PLUS_CORE_NAME}@`; + +// The core version encodes the bundled Vite version (rfcs/core-version-alignment.md), +// so it differs from the vite-plus version. Preview builds stamp the core manifest +// before the build, so `corePkg.version` is already the preview version. +export const VITE_PLUS_CORE_VERSION = process.env.VP_CORE_VERSION || corePkg.version; // Mirrors Vite's DEFAULT_CONFIG_FILES order so readers and writers target the same file. export const VITE_CONFIG_FILES = [ @@ -27,7 +36,7 @@ export const TSDOWN_MIGRATION_SKILL_URL = export const VITE_PLUS_OVERRIDE_PACKAGES: Record = process.env.VP_OVERRIDE_PACKAGES ? JSON.parse(process.env.VP_OVERRIDE_PACKAGES) : { - vite: `npm:@voidzero-dev/vite-plus-core@${VITE_PLUS_VERSION}`, + vite: `${VITE_PLUS_CORE_ALIAS_PREFIX}${VITE_PLUS_CORE_VERSION}`, // The runner inlines its assertion and runner state. Its remaining // official dependencies use exact versions; community providers and // Istanbul internals have their own version ranges. diff --git a/packages/core/BUNDLING.md b/packages/core/BUNDLING.md index e946fb9f3a..814b075f8c 100644 --- a/packages/core/BUNDLING.md +++ b/packages/core/BUNDLING.md @@ -156,7 +156,7 @@ The `rolldown_webcontainer_fallback` CLI snapshot executes the packed binding lo ### Release Build: Native Binding Rewriting -During release builds (`RELEASE_BUILD=1`), `bundleRolldown()` rewrites Rolldown's native binding requires through `build-support/rewrite-rolldown-binding.ts`. For every platform in the CLI's `napi.targets` (mapped to napi platform suffixes with `parseTriple`), the loader's `@rolldown/binding-` requires become `@voidzero-dev/vite-plus-`, and that branch's version guard switches from the Rolldown version to core's version, which is what the Vite+ platform packages are published as. +During release builds (`RELEASE_BUILD=1`), `bundleRolldown()` rewrites Rolldown's native binding requires through `build-support/rewrite-rolldown-binding.ts`. For every platform in the CLI's `napi.targets` (mapped to napi platform suffixes with `parseTriple`), the loader's `@rolldown/binding-` requires become `@voidzero-dev/vite-plus-`, and that branch's version guard switches from the Rolldown version to the CLI version, which is what the Vite+ platform packages are published as. **Platform-specific binding rewrites**, one per `napi.targets` entry in `packages/cli/package.json` (see the target table in [CLI Package Bundling](../cli/BUNDLING.md#napi-targets)), for example: @@ -171,7 +171,7 @@ Specifiers for platforms Vite+ does not ship (android, freebsd, the `wasm32-wasi 1. **Self-contained distribution** - Users don't need to install separate `@rolldown/binding-*` packages 2. **Declared dependency graph** - Core resolves the binding through its own `optionalDependencies` (injected during publish by `packages/cli/publish-native-addons.ts`), so pnpm's global virtual store and Yarn PnP work without hidden hoisting, and core no longer requires back into `vite-plus` -3. **Version alignment** - Each rewritten branch's guard checks the platform package version against core's version; both are published lockstep +3. **Version alignment** - Each rewritten branch's guard checks the platform package version against the CLI version, which the platform packages use. The core version differs (see [Core Version](#core-version)) **Resolution chain**: @@ -316,7 +316,8 @@ dist/ 1. Update the Vite pin in [`packages/tools/.upstream-versions.json`](../tools/.upstream-versions.json) and review the resolver patch against the new source 2. Follow the [upstream sync and build instructions](../../CONTRIBUTING.md#pull-upstream-dependencies) to prepare the source, regenerate Vite types, and rebuild the packages 3. Verify `bundledVersions.vite` in `package.json` is updated -4. Test with `pnpm test` +4. Set `version` in `package.json` to the encoded version for the new Vite version, for example `8.4.200` for Vite `8.4.2` (see [Core Version](#core-version)). The upgrade-deps workflow does this step automatically +5. Test with `pnpm test` ### Updating Rolldown @@ -405,3 +406,20 @@ The `bundledVersions` field in `package.json` records the exact versions of bund ``` This is automatically updated by `mergePackageJson()` during each build. + +### Core Version + +The core version encodes `bundledVersions.vite`, so it differs from the `vite-plus` version. Package managers compare the version of the `vite` alias target with the `vite` peer ranges of plugins, so the encoded version makes those checks match the bundled Vite. See [the RFC](../../rfcs/core-version-alignment.md) for the design. + +| Release | Core version | Example | +| --------------------------------------- | -------------------------------------------------- | -------------------------------- | +| Stable `vite-plus` | `..` | Vite `8.3.5`, `n = 1`: `8.3.501` | +| `vite-plus` prerelease, stable Vite | `-vp.` | `8.4.0-vp.0` | +| `vite-plus` prerelease, Vite prerelease | `.vp.` | `9.0.0-beta.3.vp.0` | +| Local and CI builds | `n = 99` | `8.3.599` | + +`n` counts the stable releases on one Vite version, from 0 to 98. `k` counts the prereleases on one base. [`packages/tools/src/core-version.ts`](../tools/src/core-version.ts) implements the scheme: + +- `prepare_release.yml` runs `core-version.ts next` to select the next unpublished version from the registry. +- `.github/scripts/upgrade-deps.ts` resets `version` to `n = 0` when the bundled Vite changes. +- `__tests__/core-version.spec.ts` checks that the committed `version` encodes `bundledVersions.vite`. diff --git a/packages/core/__tests__/core-version.spec.ts b/packages/core/__tests__/core-version.spec.ts new file mode 100644 index 0000000000..42714fea4a --- /dev/null +++ b/packages/core/__tests__/core-version.spec.ts @@ -0,0 +1,12 @@ +import { describe, expect, it } from 'vite-plus/test'; + +import cliPkg from '../../cli/package.json' with { type: 'json' }; +import { assertCoreVersionMatchesVite } from '../../tools/src/core-version.ts'; +import corePkg from '../package.json' with { type: 'json' }; + +describe('core version', () => { + // The preview flow stamps `0.0.0-commit.` on every package. + it.skipIf(corePkg.version.startsWith('0.0.0-commit.'))('encodes the bundled Vite version', () => { + expect(() => assertCoreVersionMatchesVite(corePkg, cliPkg.version)).not.toThrow(); + }); +}); diff --git a/packages/core/build-support/rewrite-rolldown-binding.ts b/packages/core/build-support/rewrite-rolldown-binding.ts index f5d1bb35ef..998760cff6 100644 --- a/packages/core/build-support/rewrite-rolldown-binding.ts +++ b/packages/core/build-support/rewrite-rolldown-binding.ts @@ -21,7 +21,7 @@ export interface RewriteRolldownBindingOptions { * are left on `@rolldown/binding-*` and keep their upstream version guards. */ platformSuffixes: ReadonlySet; - /** Version the platform packages are published as (core's own version). */ + /** Version the platform packages are published as (the CLI version). */ version: string; } diff --git a/packages/core/build.ts b/packages/core/build.ts index c3bf11b33a..44cc6bb168 100644 --- a/packages/core/build.ts +++ b/packages/core/build.ts @@ -414,7 +414,9 @@ async function bundleRolldown() { const result = rewriteRolldownBindingRequires(source, { packageName: cliPkgJson.napi.packageName, platformSuffixes: vitePlusPlatformSuffixes, - version: pkgJson.version, + // The platform packages publish at the CLI version. The core version + // encodes the bundled Vite version instead (rfcs/core-version-alignment.md). + version: cliPkgJson.version, }); source = result.source; for (const suffix of result.rewrittenSuffixes) { diff --git a/packages/core/package.json b/packages/core/package.json index f9b978e52e..24255a5391 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@voidzero-dev/vite-plus-core", - "version": "1.5.0", + "version": "8.3.500", "description": "The Unified Toolchain for the Web", "homepage": "https://viteplus.dev/guide", "bugs": { diff --git a/packages/tools/src/__tests__/core-version.spec.ts b/packages/tools/src/__tests__/core-version.spec.ts new file mode 100644 index 0000000000..961aa5c73f --- /dev/null +++ b/packages/tools/src/__tests__/core-version.spec.ts @@ -0,0 +1,149 @@ +import { describe, expect, test } from 'vitest'; + +import { + assertCoreVersionMatchesVite, + decodeCoreVersion, + encodeCoreVersion, + nextCoreVersion, +} from '../core-version.ts'; + +const PUBLISHED_BEFORE_ALIGNMENT = ['0.1.21-alpha.7', '0.0.2-test.1', '1.0.0-rc.0', '1.4.0']; + +describe('encodeCoreVersion', () => { + test('encodes the Vite patch and the release counter in the patch', () => { + expect(encodeCoreVersion('8.3.5', 0)).toBe('8.3.500'); + expect(encodeCoreVersion('8.3.5', 1)).toBe('8.3.501'); + expect(encodeCoreVersion('8.4.0', 0)).toBe('8.4.0'); + expect(encodeCoreVersion('8.4.1', 0)).toBe('8.4.100'); + expect(encodeCoreVersion('8.3.5', 99)).toBe('8.3.599'); + }); + + test('rejects a Vite prerelease and an out-of-range counter', () => { + expect(() => encodeCoreVersion('9.0.0-beta.3', 0)).toThrow('Vite prerelease'); + expect(() => encodeCoreVersion('8.3.5', 100)).toThrow('from 0 to 99'); + expect(() => encodeCoreVersion('8.3.5', -1)).toThrow('from 0 to 99'); + }); +}); + +describe('decodeCoreVersion', () => { + test('decodes stable and prerelease core versions', () => { + expect(decodeCoreVersion('8.3.500')).toEqual({ vite: '8.3.5', n: 0 }); + expect(decodeCoreVersion('8.3.501')).toEqual({ vite: '8.3.5', n: 1 }); + expect(decodeCoreVersion('8.4.1')).toEqual({ vite: '8.4.0', n: 1 }); + expect(decodeCoreVersion('8.4.0-vp.2')).toEqual({ vite: '8.4.0', n: 0, k: 2 }); + expect(decodeCoreVersion('9.0.0-beta.3.vp.1')).toEqual({ vite: '9.0.0-beta.3', k: 1 }); + }); + + test('rejects prereleases without the vp counter', () => { + expect(() => decodeCoreVersion('0.0.0-commit.0c515e3')).toThrow('not an encoded'); + expect(() => decodeCoreVersion('8.4.0-rc.0')).toThrow('not an encoded'); + expect(() => decodeCoreVersion('8.4.0-vp.x')).toThrow('not an encoded'); + expect(() => decodeCoreVersion('latest')).toThrow('Invalid version'); + }); +}); + +describe('nextCoreVersion', () => { + test('starts the counter at 0 for a new Vite version', () => { + expect( + nextCoreVersion({ vite: '8.3.5', vitePlus: '1.5.0', published: PUBLISHED_BEFORE_ALIGNMENT }), + ).toBe('8.3.500'); + }); + + test('increments the counter for each stable release on one Vite version', () => { + const published = [...PUBLISHED_BEFORE_ALIGNMENT, '8.3.500', '8.3.501', '8.3.600']; + expect(nextCoreVersion({ vite: '8.3.5', vitePlus: '1.5.2', published })).toBe('8.3.502'); + expect(nextCoreVersion({ vite: '8.3.6', vitePlus: '1.6.1', published })).toBe('8.3.601'); + expect(nextCoreVersion({ vite: '8.4.0', vitePlus: '1.7.0', published })).toBe('8.4.0'); + }); + + test('ignores prereleases and local versions for the stable counter', () => { + const published = ['8.4.0-vp.0', '8.4.0-vp.1', '8.4.99']; + expect(nextCoreVersion({ vite: '8.4.0', vitePlus: '1.7.0', published })).toBe('8.4.0'); + }); + + test('gives each Vite+ prerelease on a stable Vite a unique vp counter', () => { + expect(nextCoreVersion({ vite: '8.4.0', vitePlus: '1.7.0-rc.0', published: [] })).toBe( + '8.4.0-vp.0', + ); + expect( + nextCoreVersion({ vite: '8.4.0', vitePlus: '1.8.0-rc.0', published: ['8.4.0-vp.0'] }), + ).toBe('8.4.0-vp.1'); + expect( + nextCoreVersion({ + vite: '8.4.0', + vitePlus: '1.8.0-rc.0', + published: ['8.4.0', '8.4.0-vp.0', '8.4.0-vp.1'], + }), + ).toBe('8.4.1-vp.0'); + }); + + test('appends the vp counter to a bundled Vite prerelease', () => { + expect(nextCoreVersion({ vite: '9.0.0-beta.3', vitePlus: '2.0.0-beta.0', published: [] })).toBe( + '9.0.0-beta.3.vp.0', + ); + expect( + nextCoreVersion({ + vite: '9.0.0-beta.3', + vitePlus: '2.0.0-beta.1', + published: ['9.0.0-beta.2.vp.4', '9.0.0-beta.3.vp.0'], + }), + ).toBe('9.0.0-beta.3.vp.1'); + }); + + test('rejects a stable vite-plus release on a Vite prerelease', () => { + expect(() => + nextCoreVersion({ vite: '9.0.0-beta.3', vitePlus: '2.0.0', published: [] }), + ).toThrow('cannot bundle the Vite prerelease'); + }); + + test('fails when the release counter is exhausted', () => { + const published = Array.from({ length: 99 }, (_, n) => encodeCoreVersion('8.3.5', n)); + expect(() => nextCoreVersion({ vite: '8.3.5', vitePlus: '1.9.0', published })).toThrow( + 'the maximum', + ); + }); +}); + +function manifest(version: string, vite = '8.3.5') { + return { version, bundledVersions: { vite } }; +} + +describe('assertCoreVersionMatchesVite', () => { + test('accepts a core version that encodes the bundled Vite', () => { + expect(() => assertCoreVersionMatchesVite(manifest('8.3.500'), '1.5.0')).not.toThrow(); + expect(() => assertCoreVersionMatchesVite(manifest('8.3.599'), '0.0.0')).not.toThrow(); + expect(() => + assertCoreVersionMatchesVite(manifest('8.4.0-vp.1', '8.4.0'), '1.7.0-rc.1'), + ).not.toThrow(); + expect(() => + assertCoreVersionMatchesVite(manifest('9.0.0-beta.3.vp.0', '9.0.0-beta.3'), '2.0.0-beta.0'), + ).not.toThrow(); + }); + + test('rejects a core version that encodes another Vite version', () => { + expect(() => assertCoreVersionMatchesVite(manifest('8.3.400'), '1.5.0')).toThrow( + 'Set its version to 8.3.500', + ); + expect(() => assertCoreVersionMatchesVite(manifest('1.4.0'), '1.4.0')).toThrow( + 'encodes Vite 1.4.0', + ); + }); + + test('rejects mixed prerelease and stable versions', () => { + expect(() => assertCoreVersionMatchesVite(manifest('8.3.500'), '1.5.0-rc.0')).toThrow( + 'both be prereleases', + ); + expect(() => assertCoreVersionMatchesVite(manifest('8.3.500-vp.0'), '1.5.0')).toThrow( + 'both be prereleases', + ); + }); + + test('rejects the local build counter for a release', () => { + expect(() => + assertCoreVersionMatchesVite(manifest('8.3.599'), '1.5.0', { release: true }), + ).toThrow('reserved for local builds'); + expect(() => + assertCoreVersionMatchesVite(manifest('8.3.598'), '1.5.0', { release: true }), + ).not.toThrow(); + }); +}); diff --git a/packages/tools/src/core-version.ts b/packages/tools/src/core-version.ts new file mode 100644 index 0000000000..4917b71c2f --- /dev/null +++ b/packages/tools/src/core-version.ts @@ -0,0 +1,278 @@ +/** + * Version scheme of `@voidzero-dev/vite-plus-core` (rfcs/core-version-alignment.md). + * + * The core version encodes the bundled Vite version, so package managers check + * `vite` peer ranges against the alias `vite: npm:@voidzero-dev/vite-plus-core@...` + * correctly: + * + * stable Vite+ release: .. + * Vite+ prerelease, stable Vite: -vp. + * Vite+ prerelease, Vite pre: .vp. + * + * `n` counts the stable Vite+ releases on one Vite version (0 to 98). `n = 99` + * is reserved for local and CI builds, so they never collide with a published + * version. `k` counts the Vite+ prereleases on one base. + * + * Usage: + * node packages/tools/src/core-version.ts next --vite-plus + * node packages/tools/src/core-version.ts local + * node packages/tools/src/core-version.ts check [--release] + */ + +import { execFileSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { parseArgs } from 'node:util'; + +export const CORE_PACKAGE_NAME = '@voidzero-dev/vite-plus-core'; +/** The `vite` alias to the core: `npm:@voidzero-dev/vite-plus-core@`. */ +export const CORE_ALIAS_PREFIX = `npm:${CORE_PACKAGE_NAME}@`; +const MAX_RELEASE_COUNTER = 98; +const LOCAL_BUILD_COUNTER = 99; + +const PRERELEASE_TAG = 'vp'; +const VERSION_RE = + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/; + +interface ParsedVersion { + major: number; + minor: number; + patch: number; + prerelease: string[]; +} + +export interface DecodedCoreVersion { + /** The bundled Vite version. */ + vite: string; + /** The stable release counter. Undefined on a Vite prerelease. */ + n?: number; + /** The Vite+ prerelease counter. Undefined on a stable core version. */ + k?: number; +} + +function parseVersion(version: string): ParsedVersion { + const match = VERSION_RE.exec(version); + if (!match) { + throw new Error(`Invalid version: ${version}`); + } + return { + major: Number(match[1]), + minor: Number(match[2]), + patch: Number(match[3]), + prerelease: match[4] ? match[4].split('.') : [], + }; +} + +function isPrereleaseVersion(version: string): boolean { + return parseVersion(version).prerelease.length > 0; +} + +/** Returns the stable core version for release counter `n` on a stable Vite. */ +export function encodeCoreVersion(vite: string, n: number): string { + const { major, minor, patch, prerelease } = parseVersion(vite); + if (prerelease.length > 0) { + throw new Error(`A stable core version cannot encode the Vite prerelease ${vite}`); + } + if (!Number.isInteger(n) || n < 0 || n > LOCAL_BUILD_COUNTER) { + throw new Error(`The release counter must be an integer from 0 to ${LOCAL_BUILD_COUNTER}`); + } + return `${major}.${minor}.${patch * 100 + n}`; +} + +/** Decodes a core version into the bundled Vite version and its counters. */ +export function decodeCoreVersion(core: string): DecodedCoreVersion { + const { major, minor, patch, prerelease } = parseVersion(core); + const stableVite = `${major}.${minor}.${Math.floor(patch / 100)}`; + if (prerelease.length === 0) { + return { vite: stableVite, n: patch % 100 }; + } + const k = prerelease.at(-1)!; + if (prerelease.at(-2) !== PRERELEASE_TAG || !/^(?:0|[1-9]\d*)$/.test(k)) { + throw new Error(`${core} is not an encoded core version`); + } + if (prerelease.length === 2) { + return { vite: stableVite, n: patch % 100, k: Number(k) }; + } + return { + vite: `${major}.${minor}.${patch}-${prerelease.slice(0, -2).join('.')}`, + k: Number(k), + }; +} + +export function tryDecodeCoreVersion(core: string): DecodedCoreVersion | undefined { + try { + return decodeCoreVersion(core); + } catch { + return undefined; + } +} + +function nextCounter(values: Iterable): number { + let next = 0; + for (const value of values) { + next = Math.max(next, value + 1); + } + return next; +} + +/** + * Returns the core version for a release. + * + * @param vite - The bundled Vite version. + * @param vitePlus - The `vite-plus` version of the release. + * @param published - Every published core version. Versions from before the + * alignment (the `0.x` and `1.x` lines) never match a bundled Vite version, + * so they do not affect the counters. + */ +export function nextCoreVersion({ + vite, + vitePlus, + published, +}: { + vite: string; + vitePlus: string; + published: readonly string[]; +}): string { + const isVitePlusPrerelease = isPrereleaseVersion(vitePlus); + const decoded = published.flatMap((version) => { + const result = tryDecodeCoreVersion(version); + return result ? [result] : []; + }); + + if (isPrereleaseVersion(vite)) { + if (!isVitePlusPrerelease) { + throw new Error(`The stable vite-plus ${vitePlus} cannot bundle the Vite prerelease ${vite}`); + } + const k = nextCounter( + decoded.flatMap((entry) => (entry.vite === vite && entry.k !== undefined ? [entry.k] : [])), + ); + return `${vite}.${PRERELEASE_TAG}.${k}`; + } + + const n = nextCounter( + decoded.flatMap((entry) => + entry.vite === vite && + entry.k === undefined && + entry.n !== undefined && + entry.n <= MAX_RELEASE_COUNTER + ? [entry.n] + : [], + ), + ); + if (n > MAX_RELEASE_COUNTER) { + throw new Error( + `Vite ${vite} already has ${MAX_RELEASE_COUNTER + 1} core releases, the maximum`, + ); + } + const base = encodeCoreVersion(vite, n); + if (!isVitePlusPrerelease) { + return base; + } + const k = nextCounter( + decoded.flatMap((entry) => + entry.vite === vite && entry.n === n && entry.k !== undefined ? [entry.k] : [], + ), + ); + return `${base}-${PRERELEASE_TAG}.${k}`; +} + +/** + * Asserts that a core manifest encodes its bundled Vite version, and that the + * core version is a prerelease exactly when the `vite-plus` version is one. + * With `release`, also rejects the local build counter. + */ +export function assertCoreVersionMatchesVite( + pkg: { version: string; bundledVersions?: { vite?: string } }, + vitePlus: string, + { release = false }: { release?: boolean } = {}, +): void { + const vite = pkg.bundledVersions?.vite; + if (!vite) { + throw new Error(`${CORE_PACKAGE_NAME} has no bundledVersions.vite`); + } + const decoded = decodeCoreVersion(pkg.version); + if (decoded.vite !== vite) { + throw new Error( + `${CORE_PACKAGE_NAME}@${pkg.version} encodes Vite ${decoded.vite}, but it bundles Vite ${vite}. ` + + `Set its version to ${isPrereleaseVersion(vite) ? `${vite}.${PRERELEASE_TAG}.0` : encodeCoreVersion(vite, 0)}.`, + ); + } + const isCorePrerelease = decoded.k !== undefined; + if (isCorePrerelease !== isPrereleaseVersion(vitePlus)) { + throw new Error( + `${CORE_PACKAGE_NAME}@${pkg.version} and vite-plus@${vitePlus} must both be prereleases or both be stable`, + ); + } + if (release && decoded.n === LOCAL_BUILD_COUNTER) { + throw new Error( + `${CORE_PACKAGE_NAME}@${pkg.version} uses the counter ${LOCAL_BUILD_COUNTER}, which is reserved for local builds`, + ); + } +} + +function readManifest(relativePath: string): { + version: string; + bundledVersions?: { vite?: string }; +} { + return JSON.parse(readFileSync(new URL(relativePath, import.meta.url), 'utf8')); +} + +function readPublishedCoreVersions(): string[] { + const output = execFileSync('npm', ['view', CORE_PACKAGE_NAME, 'versions', '--json'], { + encoding: 'utf8', + }); + const versions: unknown = JSON.parse(output); + if (typeof versions === 'string') { + return [versions]; + } + if (!Array.isArray(versions) || versions.some((version) => typeof version !== 'string')) { + throw new Error(`Unexpected output from npm view ${CORE_PACKAGE_NAME} versions`); + } + return versions; +} + +function main(argv: string[]): void { + const { positionals, values } = parseArgs({ + args: argv, + allowPositionals: true, + options: { + 'vite-plus': { type: 'string' }, + release: { type: 'boolean', default: false }, + }, + }); + const core = readManifest('../../core/package.json'); + const vite = core.bundledVersions?.vite; + if (!vite) { + throw new Error(`packages/core/package.json has no bundledVersions.vite`); + } + + switch (positionals[0]) { + case 'next': { + const vitePlus = values['vite-plus']; + if (!vitePlus) { + throw new Error('next requires --vite-plus '); + } + console.log(nextCoreVersion({ vite, vitePlus, published: readPublishedCoreVersions() })); + break; + } + case 'local': + console.log(encodeCoreVersion(vite, LOCAL_BUILD_COUNTER)); + break; + case 'check': { + const cli = readManifest('../../cli/package.json'); + assertCoreVersionMatchesVite(core, cli.version, { release: values.release }); + console.log(`${CORE_PACKAGE_NAME}@${core.version} encodes Vite ${vite}`); + break; + } + default: + throw new Error(`Unknown command: ${positionals[0] ?? ''}. Use next, local, or check.`); + } +} + +if (import.meta.main) { + try { + main(process.argv.slice(2)); + } catch (error) { + console.error(`[core-version] ${(error as Error).message}`); + process.exit(1); + } +} diff --git a/rfcs/core-version-alignment.md b/rfcs/core-version-alignment.md new file mode 100644 index 0000000000..f50d9883aa --- /dev/null +++ b/rfcs/core-version-alignment.md @@ -0,0 +1,591 @@ +# RFC: Align the Core Package Version with the Bundled Vite Version + +- Status: Proposed +- Issue: [#2806](https://github.com/voidzero-dev/vite-plus/issues/2806) +- Related: [Q4 2026 plan](https://github.com/voidzero-dev/vite-plus/issues/3277), + [Vite core module identity](./vite-core-module-identity.md), + [Core binding resolution](./core-binding-resolution.md), + [Migration rules](../docs/guide/migrate-rules.md), + [Core package bundling](../packages/core/BUNDLING.md) + +## Proposal + +Derive the version of `@voidzero-dev/vite-plus-core` from the Vite version it +bundles. The core major and minor equal the bundled Vite major and minor. The +core patch encodes the bundled Vite patch and a release counter: + +```text +stable Vite+ release: .. +Vite+ prerelease, stable Vite: -vp. +Vite+ prerelease, Vite pre: .vp. +``` + +`n` counts the stable Vite+ releases that bundle the same Vite patch, from 0 +to 98. `n = 99` is reserved for local and CI builds. `k` counts the Vite+ +prereleases on the same base, from 0. Decoding is exact: the bundled Vite +patch is `floor(core patch / 100)`. + +| Vite+ release | Bundled Vite | Core version | +| ----------------- | -------------- | ------------------- | +| `1.5.0` (first) | `8.3.5` | `8.3.500` | +| `1.5.1` | `8.3.5` | `8.3.501` | +| `1.6.0` | `8.3.6` | `8.3.600` | +| `1.7.0-rc.0` | `8.4.0` | `8.4.0-vp.0` | +| `1.7.0-rc.1` | `8.4.0` | `8.4.0-vp.1` | +| `1.7.0` | `8.4.0` | `8.4.0` | +| `1.7.1` | `8.4.1` | `8.4.100` | +| `2.0.0-beta.0` | `9.0.0-beta.3` | `9.0.0-beta.3.vp.0` | +| `2.0.0-beta.1` | `9.0.0-beta.3` | `9.0.0-beta.3.vp.1` | +| Local or CI build | `8.3.5` | `8.3.599` | + +`vite-plus` keeps its own version line (`1.x` today). The CLI keeps its exact +alias dependency `vite: npm:@voidzero-dev/vite-plus-core@`. +Projects keep the same alias in their manifests, overrides, catalogs, and +resolutions. `vp migrate` stops adding `vite` to pnpm `peerDependencyRules` +and removes the entry that earlier migrations wrote. + +## Problem + +A migrated project aliases `vite` to the core package: + +```json +{ + "devDependencies": { + "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0", + "vite-plus": "1.4.0" + } +} +``` + +Package managers resolve the alias and read the target's manifest. They +compare its `version` (`1.4.0`) with each consumer's `vite` peer range. Every +current plugin range fails: `vitest@5.0.5` declares +`^6.4.0 || ^7.0.0 || ^8.0.0`, `@vitejs/plugin-react@6.1.2` declares `^8.0.0`, +`@tanstack/react-start` declares `>=8.0.0`. + +pnpm users need `peerDependencyRules.allowAny: [vite]` and +`allowedVersions: { vite: '*' }`. `vp migrate` writes these rules in +`packages/cli/src/migration/migrator/vite-plus-bootstrap.ts` +(`ensurePnpmPeerDependencyRules`), `catalog.ts` (`rewritePnpmWorkspaceYaml`), +and `orchestrators.ts`. The rules also hide real incompatibilities: a plugin +that declares `vite: ^7.0.0` installs without a warning. + +npm has no per-package suppression. The `vite-plus` package alone is +inconsistent from npm's point of view: it depends on +`vite: npm:@voidzero-dev/vite-plus-core@1.4.0` and on `vitest`, whose peer +range rejects `1.4.0`. Every `npm install` prints +`ERESOLVE overriding peer dependency` warnings, and `npm ls vite` marks the +alias `invalid`. The only workaround is `legacy-peer-deps=true`, which changes +peer resolution for the whole tree. + +The release pipeline sets one version on every package. +`.github/workflows/prepare_release.yml` runs `update_json` on +`packages/cli/package.json` and `packages/core/package.json` with the same +`VERSION`. `.github/workflows/release.yml` publishes +`@voidzero-dev/vite-plus-core@${VERSION}`, and +`.github/workflows/reusable-release-build.yml` stamps `${VERSION}` into both +manifests before the build. + +## Goals and scope + +For a project whose bundled Vite satisfies a consumer's `vite` peer range, +the package manager must report the peer as satisfied. For a consumer whose +range excludes the bundled Vite major or minor, the package manager must still +report it. Patch-level floors must resolve correctly up to the bundled patch. + +Migration must stop writing the broad `vite` peer rule and must remove the one +it wrote earlier, without touching rules that users added for other packages. + +The core version must be derivable from the bundled Vite version, and the +bundled Vite version from the core version, without a lookup table. CI must +check that the committed core version encodes `bundledVersions.vite`. + +Out of scope: + +- The `vitest` entries in the same peer rules. `vitest` is pinned to a real + upstream version (`VITEST_VERSION` in `packages/cli/src/utils/constants.ts`), + so peer checks against it are already accurate. The `vitest` rule hides + real incompatibilities in the same way; removing it is a separate change. +- The `vite-plus` version policy. This RFC does not decide whether a Vite + major upgrade is a `vite-plus` major release. +- The registry bridge for preview builds. It assigns `0.0.0-commit.` to + every workspace package and is a separate repository. + +## Design + +### Version scheme + +The scheme must make four range shapes resolve like the bundled Vite: +`^MAJOR.0.0`, `^MAJOR.MINOR.0`, `~MAJOR.MINOR.0`, and `>=MAJOR.MINOR.PATCH`. +Three options were compared against bundled Vite `8.3.5` with `vite-plus` +`1.4.0`: + +- Option A: core major = Vite major; minor and patch follow `vite-plus` + (`8.4.0`). +- Option B: core major and minor = Vite major and minor; patch is a plain + counter per Vite+ release (`8.3.0`, `8.3.1`, ...). +- Option B+ (selected): like B, but the patch encodes the Vite patch + (`8.3.500`, `8.3.501`, ...). +- Option C: core = exact Vite version plus a prerelease tag + (`8.3.5-vp.1.4.0`) or build metadata (`8.3.5+vp.1.4.0`). + +| Consumer range | Bundled `8.3.5` | A `8.4.0` | B `8.3.0` | B+ `8.3.500` | C `8.3.5-vp.1.4.0` (npm) | +| -------------- | --------------- | ------------ | ------------ | ------------ | ------------------------ | +| `^8.0.0` | pass | pass | pass | pass | fail (wrong) | +| `^8.3.0` | pass | pass | pass | pass | fail (wrong) | +| `>=8.3.2` | pass | pass | fail (wrong) | pass | fail (wrong) | +| `~8.3.0` | pass | fail (wrong) | pass | pass | fail (wrong) | +| `^7.0.0` | fail | fail | fail | fail | fail | +| `^8.4.0` | fail | pass (wrong) | fail | fail | fail | +| `>=8.3.6` | fail | pass (wrong) | fail | pass (wrong) | fail | + +Option A fails on minor ranges in both directions. The `vite-plus` minor and +the Vite minor drift apart: `v1.2.0` bundled Vite `8.3.4`, so core `8.2.0` +would reject `^8.3.0` consumers, and a later `vite-plus` `1.9.x` on Vite +`8.5.x` would accept `>=8.6.0` consumers. Both are the failure the RFC exists +to remove. + +Option B resolves minor ranges correctly. Its patch carries no information, so +a `>=8.3.2` consumer fails against `8.3.0` or `8.3.1` although the bundled +`8.3.5` satisfies it. A consumer `>=8.3.6` passes when the counter reaches +the value 6. Patch floors are less common than minor floors, but they exist, +and the counter value is unrelated to the real patch in both directions. + +Option C fails the main goal. npm's semver compares a prerelease only against +comparators with the same `major.minor.patch` tuple, so `8.3.5-vp.1.4.0` +fails `^8.0.0`, `>=8.0.0`, and `^8.3.0`. npm users keep every warning from +#2806. The experiment below confirms this behavior for npm and shows that pnpm +and Yarn are more lenient. Build metadata does not help: npm treats +`8.3.5+a` and `8.3.5+b` as the same version, so a second Vite+ release on the +same Vite patch cannot publish. `v1.2.0` and `v1.3.0` both bundled Vite +`8.3.4`, so that case is real. + +Option B+ is the selected scheme. Its residual false results are limited to +patch floors above the bundled patch inside the same minor (`>=8.3.6` passes +against `8.3.500`) and to exact pins (`8.3.5` fails against `8.3.500`). Both +are rare in `vite` peer ranges. Vite+ follows Vite patch releases within days, +so the window for the first case is short. + +The counter supports 99 stable Vite+ releases per Vite patch (`n` from 0 to +98). `n = 99` is reserved for local and CI builds (see Local and CI builds). +Vite+ shipped five minor releases between 2026-09-28 and 2026-10-23 while Vite +moved from `8.3.1` to `8.3.5`. Two releases on one Vite patch happened once +(`v1.2.0` and `v1.3.0` on `8.3.4`). + +Core versions keep sorting correctly: +`8.3.501 < 8.3.502-vp.0 < 8.3.502 < 8.3.600`. + +### Prereleases and new Vite majors + +A Vite+ prerelease does not copy its own prerelease identifiers into the core +version. A copied suffix has two problems: + +- Two Vite+ prereleases can have the same identifiers, for example + `1.7.0-rc.0` and `1.8.0-rc.0`. If no stable release ships between them on + the same Vite, both map to `8.4.0-rc.0`, and the second publish fails. +- On a stable Vite, a copied suffix looks like a Vite prerelease and can sort + out of order. A Vite+ RC on Vite `9.0.0` would publish `9.0.0-rc.0`, which + sorts below a core built on Vite `9.0.0-rc.1`. + +Every Vite+ prerelease uses the identifier `vp` and a counter `k` instead: + +- On a stable Vite `X.Y.Z`, the base is the next stable core version, which + is the version that the next stable release on that Vite would get. The core + version is that base with `-vp.` appended. `k` counts the published core + prereleases with the same base, from 0. Vite+ `1.7.0-rc.0` and `1.7.0-rc.1` + on Vite `8.4.0` publish `8.4.0-vp.0` and `8.4.0-vp.1`. A later `1.8.0-rc.0` + on the same Vite, with no stable release between them, publishes + `8.4.0-vp.2`. The next stable release publishes `8.4.0`. +- On a Vite prerelease `X.Y.Z-
`, the core version is the Vite version
+  with `.vp.` appended. `k` counts the published core prereleases for that
+  Vite prerelease. Vite `9.0.0-beta.3` gives `9.0.0-beta.3.vp.0`, then
+  `9.0.0-beta.3.vp.1`.
+
+The `vite-plus` prerelease identifiers do not appear in the core version. The
+exact alias in the published CLI manifest links the two versions, as it does
+for stable releases (see Relation to the `vite-plus` version).
+
+The identifier `vp` sorts after `alpha`, `beta`, and `rc`, so every core
+version is unique and in publish order. `semver@7.8.5` gives this order:
+
+```text
+9.0.0-beta.3 < 9.0.0-beta.3.vp.0 < 9.0.0-beta.3.vp.1 < 9.0.0-beta.4
+  < 9.0.0-rc.1.vp.0 < 9.0.0-vp.0 < 9.0.0-vp.1 < 9.0.0
+  < 9.0.100-vp.0 < 9.0.100
+```
+
+With `semver@7.8.5` and npm's strict prerelease rules, `9.0.0-beta.3.vp.0`
+satisfies `^9.0.0-0` and `^9.0.0-beta.1`. This form was not tested in pnpm,
+Yarn, or Bun.
+
+A core prerelease on a stable Vite still fails strict peer checks in npm:
+`8.4.0-vp.0` does not satisfy `^8.0.0`. Prereleases are opt-in, so this RFC
+accepts the warnings for that period. Migration keeps the pnpm peer rule for
+prerelease core versions (see Migration).
+
+A Vite+ stable release bundles a stable Vite. Only a Vite+ prerelease may
+bundle a Vite prerelease. CI rejects a core prerelease on a `vite-plus`
+version without a prerelease identifier, and a stable core on a `vite-plus`
+prerelease.
+
+Since `v1.0.0`, Vite+ published no prereleases. The last ones are
+`v1.0.0-rc.0` and `v1.0.0-rc.1`. The prerelease rule matters mostly for the
+Vite 9 beta period.
+
+A new Vite major gives a new core major (`9.0.0` for Vite `9.0.0`). The
+`vite-plus` version does not follow. A Vite major upgrade is a breaking change
+for user plugins, so a `vite-plus` major release is the expected choice, but
+that decision stays with the release policy.
+
+### Relation to the `vite-plus` version
+
+`vite-plus` stays on its own version line. The two versions are linked by the
+exact alias in the published CLI manifest. pnpm already rewrites
+`vite: workspace:@voidzero-dev/vite-plus-core@*` in
+`packages/cli/package.json` to `npm:@voidzero-dev/vite-plus-core@`
+at pack time, using the core package's own version. That mechanism needs no
+change.
+
+Code that assumes the two versions are equal must change:
+
+| Location                                                | Current behavior                                                      | Required change                                                                                                                                                 |
+| ------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `packages/cli/src/utils/constants.ts`                   | `VITE_PLUS_OVERRIDE_PACKAGES.vite` uses `VITE_PLUS_VERSION`           | Add `VITE_PLUS_CORE_VERSION = process.env.VP_CORE_VERSION \|\| corePkg.version`, read from `packages/core/package.json` at build time, and use it for the alias |
+| `packages/cli/src/resolve-core.ts`                      | Expects the core `version` to equal the installed `vite-plus` version | Parse the alias in the installed `vite-plus/package.json` `dependencies.vite`; skip the version check for a `workspace:` spec (repository layout)               |
+| `packages/cli/src/sync-versions/protocol.ts`, `plan.ts` | Maps `@voidzero-dev/vite-plus-core` to `toolchain.vitePlus`           | Add `vitePlusCore` from the `vite-plus-core` manifest node and map the core name to it                                                                          |
+| `packages/cli/src/migration/migrator/*`                 | Alias written through `VITE_PLUS_OVERRIDE_PACKAGES`                   | No change beyond the constant; the summary in `collectToolchainVersionChanges` already shows the raw Vite version                                               |
+| `ecosystem-ci/patch-project.ts`                         | `VP_OVERRIDE_PACKAGES.vite` uses the `vite-plus` tarball version      | Use the packed core version                                                                                                                                     |
+| `packages/tools/src/install-global-cli.ts`              | Maps the alias version to `voidzero-dev-vite-plus-core-.tgz` | No change; the alias already carries the core version after pack                                                                                                |
+| `crates/vp_global_cli/src/commands/version.rs`          | Reads `bundledVersions` from the installed core manifest              | No change                                                                                                                                                       |
+| `packages/cli/toolchain.config.json`                    | `vite-plus-core` node uses `core-package` as its version source       | No change; `vp toolchain` shows the core version and the bundled Vite version as separate nodes                                                                 |
+
+The `vp upgrade` command in `crates/vp_global_cli/src/commands/upgrade/`
+installs the global CLI from the published `vite-plus` package and its
+lockfile. It does not read the core version.
+
+### Where the version is computed and checked
+
+Add a small module, `packages/tools/src/core-version.ts`, with four pure
+functions and a CLI entry:
+
+- `encodeCoreVersion(vite, n)` returns the stable core version.
+- `decodeCoreVersion(core)` returns `{ vite, n, k }` or an error.
+- `nextCoreVersion({ vite, vitePlus, published })` returns the core version
+  for a release. Its inputs are the bundled Vite version, the `vite-plus`
+  version, and the published core versions. It applies the counter rules
+  below.
+- `assertCoreVersionMatchesVite(pkg, vitePlus)` asserts that `pkg.version`
+  decodes to `pkg.bundledVersions.vite`. It also asserts that the core
+  version is a prerelease only when the `vite-plus` version is a prerelease.
+
+The name `checkCoreVersion` is not used, because
+`packages/cli/src/resolve-core.ts` already defines a function with that name
+for the installed-core check.
+
+Counter rules in `nextCoreVersion`:
+
+- Stable release: `n` is the highest `n` among published stable core versions
+  with the same Vite version, plus 1, or 0 when none exists. If `n` would be
+  higher than 98, the function fails.
+- Prerelease on a stable Vite: the base is the version that the stable rule
+  gives. `k` is the highest `k` among published `-vp.*` versions, plus
+  1, or 0 when none exists.
+- Prerelease on a Vite prerelease: `k` is the highest `k` among published
+  `.vp.*` versions, plus 1, or 0 when none exists.
+
+The committed `packages/core/package.json` must always encode the committed
+`bundledVersions.vite`. Two writers keep it consistent:
+
+1. `.github/scripts/upgrade-deps.ts` already reads
+   `packages/core/package.json` to sync `postcss` and `fsevents`. After a
+   bundled Vite change it sets `version` to `encodeCoreVersion(vite, 0)`.
+   Renovate ignores `vite` (`.github/renovate.json`), so this script is the
+   only automated path that changes the bundled Vite.
+2. `prepare_release.yml` computes the release version. It reads the
+   published core versions
+   (`npm view @voidzero-dev/vite-plus-core versions --json`) and calls
+   `nextCoreVersion` with the input `vite-plus` version. It then writes the
+   result with the existing `update_json` helper and prints both versions in
+   the release PR body.
+
+A unit test in `packages/core/__tests__/` runs `assertCoreVersionMatchesVite`
+against the committed manifest. It skips the check when the version starts
+with `0.0.0-commit.`, which the preview flow stamps. `packages/core/build.ts`
+does not rewrite `version`: it runs after the release stamp and would race
+with it.
+
+### Local and CI builds
+
+`test-vp-create.yml` and `reusable-ecosystem-ci.yml` set both packages to
+`0.0.0` today (`npm pkg set version=0.0.0`), so that a correct install of the
+local build is easy to detect. Core `0.0.0` does not encode a Vite version,
+and peer checks fail against it. These flows would not test the path without a
+`vite` peer rule that users get.
+
+These flows will set core to `encodeCoreVersion(vite, 99)`, for example
+`8.3.599` for Vite `8.3.5`. They keep `0.0.0` for the CLI, which
+`ecosystem-ci/verify-install.ts` and `test-vp-create.yml` assert. The CLI
+reads the core version from `VP_CORE_VERSION` or from the core manifest, so
+`vp create` and `vp migrate` in these flows write the `8.3.599` alias and
+remove the `vite` peer rule.
+
+`nextCoreVersion` never returns `n = 99`, and `release.yml` rejects it.
+Thus a local version never reaches the registry, and the local registry
+cannot mix it up with a published version.
+
+### Release pipeline changes
+
+| File                                                                                                                             | Change                                                                                                                                                                                                                                                                                                                                                                        |
+| -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `.github/workflows/prepare_release.yml`                                                                                          | Compute the core version as described above; stop passing `VERSION` to `update_json packages/core/package.json`                                                                                                                                                                                                                                                               |
+| `.github/workflows/release.yml`                                                                                                  | Read `CORE_VERSION` from `packages/core/package.json` at job start, and reject a version with `n = 99`; use it in "Publish core dependency tier", "Wait for core to propagate", the release notes, and the Discord embed. After publish, check that the core `latest` dist-tag equals `CORE_VERSION`. The version check against `unpkg.com/vite-plus@latest` stays on the CLI |
+| `.github/workflows/reusable-release-build.yml`                                                                                   | Stamp `packages/core/package.json` only for preview versions (`0.0.0-commit.*`). A release checkout already carries the encoded version. Update the verify step to the same rule                                                                                                                                                                                              |
+| `packages/core/build.ts`                                                                                                         | Pass `cliPkgJson.version` instead of `pkgJson.version` to `rewriteRolldownBindingRequires`. The platform packages publish at the CLI version, and the guard must compare against that version (`packages/core/build-support/rewrite-rolldown-binding.ts`)                                                                                                                     |
+| `packages/cli/publish-native-addons.ts`                                                                                          | No change: it mirrors the CLI's platform pins into core by name and does not use the core version                                                                                                                                                                                                                                                                             |
+| `.github/workflows/publish-preview.yml`, `publish-preview-register.yml`                                                          | No change: the bridge serves every workspace package as `0.0.0-commit.`, and the stamp before `pnpm pack` keeps the alias on that version. The sticky comment keeps printing one version for both packages                                                                                                                                                               |
+| `.github/workflows/test-vp-create.yml`, `reusable-ecosystem-ci.yml`                                                              | Keep `0.0.0` for the CLI. Set core to `encodeCoreVersion(vite, 99)` and pass it as `VP_CORE_VERSION` where the workflow passes `VP_VERSION` (see Local and CI builds)                                                                                                                                                                                                         |
+| `packages/tools/src/local-npm-registry.ts`, `pack-local-vite-plus.ts`                                                            | No change: both serve the packed tarball's own version                                                                                                                                                                                                                                                                                                                        |
+| `.github/scripts/upgrade-deps.ts`                                                                                                | Reset the core version after a bundled Vite change                                                                                                                                                                                                                                                                                                                            |
+| `.github/renovate.json`                                                                                                          | No change                                                                                                                                                                                                                                                                                                                                                                     |
+| `.github/scripts/update-homebrew-formula.mjs`                                                                                    | Read the core version from the `vite` alias of the published `vite-plus` manifest, and wait for core at that version                                                                                                                                                                                                                                                          |
+| `.claude/skills/release-manager/SKILL.md`                                                                                        | Read both versions from the release branch; publish checks use the core version for core                                                                                                                                                                                                                                                                                      |
+| `packages/core/BUNDLING.md`                                                                                                      | Document the version scheme next to `bundledVersions`                                                                                                                                                                                                                                                                                                                         |
+| `MAINTENANCE.md`                                                                                                                 | Mention the two versions in the release description                                                                                                                                                                                                                                                                                                                           |
+| `README.md`, `packages/cli/README.md`, `docs/guide/local-cli.md`, `docs/guide/upgrade-project.md`, `docs/guide/migrate-rules.md` | Replace `` in alias examples with `` and point to `vp toolchain vite-plus-core`; describe the new pnpm peer rule behavior                                                                                                                                                                                                                    |
+
+### Package-manager behavior
+
+The experiment ran on macOS with pnpm `12.11.2`, npm `10.9.9`, Yarn
+`4.18.1` (`nodeLinker: node-modules`), and Bun `1.4.4`. Each project
+declared `vite` as an npm alias to a published package and local `file:`
+consumers with one `vite` peer range each. `commander@8.3.0`,
+`commander@8.0.0`, and `commander@9.0.0-0` stood in for future core versions;
+`@voidzero-dev/vite-plus-core@1.4.0` is the current core;
+`vite@8.3.0-beta.1` stood in for a prerelease core.
+
+pnpm, npm, and Yarn resolve the alias and compare the target's manifest
+version with the consumer's range. Their results for release versions agree:
+
+| Alias target | `^8.0.0` | `^8.3.0` | `>=8.3.2` | `~8.3.0` | `^7.0.0` | `^8.0.0-0` | `>=8.0.0-0` |
+| ------------ | -------- | -------- | --------- | -------- | -------- | ---------- | ----------- |
+| `8.3.0`      | ok       | ok       | unmet     | ok       | unmet    | ok         | ok          |
+| `8.0.0`      | ok       | unmet    | unmet     | unmet    | unmet    | ok         | ok          |
+| core `1.4.0` | unmet    | unmet    | unmet     | unmet    | unmet    | unmet      | unmet       |
+
+Prerelease targets differ by package manager:
+
+| Alias target   | Manager | `^8.0.0` | `^8.3.0` | `^8.0.0-0` | `^8.3.0-0` | `>=8.0.0-0` | `>=8.0.0` |
+| -------------- | ------- | -------- | -------- | ---------- | ---------- | ----------- | --------- |
+| `8.3.0-beta.1` | npm     | unmet    | unmet    | unmet      | ok         | unmet       | unmet     |
+| `8.3.0-beta.1` | pnpm    | ok       | unmet    | ok         | ok         | ok          | ok        |
+| `8.3.0-beta.1` | Yarn    | ok       | ok       | ok         | ok         | ok          | ok        |
+| `9.0.0-0`      | npm     | unmet    | unmet    | unmet      | unmet      | unmet       | unmet     |
+| `9.0.0-0`      | pnpm    | unmet    | unmet    | unmet      | unmet      | ok          | ok        |
+| `9.0.0-0`      | Yarn    | unmet    | unmet    | unmet      | unmet      | ok          | ok        |
+
+npm follows strict semver prerelease rules. pnpm includes prereleases when
+comparing. Yarn accepted `8.3.0-beta.1` for `^8.3.0`; the RFC records that
+result without a cause.
+
+Severity: pnpm prints `WARN Issues with peer dependencies found` and exits 0
+unless `strict-peer-dependencies` is set; `pnpm peers check` lists each
+consumer. npm prints `ERESOLVE overriding peer dependency` warnings and exited
+0 in every case here. Yarn prints `YN0060` and exits 0. Bun printed no peer
+diagnostic in any case, including a published consumer
+(`@vitejs/plugin-react@6.1.2`, peer `^8.0.0`) against core `1.4.0`. Bun
+resolved the alias and listed it as `vite@1.4.0`. Whether Bun checks peer
+ranges in other layouts is unverified.
+
+The current `vite-plus` manifest triggers the npm warning on its own, because
+`vitest` is a dependency with a `vite` peer range. With core `8.3.500` that
+range is satisfied, so a project that depends only on `vite-plus` installs
+without the warning.
+
+## Migration
+
+### Existing projects
+
+`vp migrate` on a project that already uses Vite+ runs the toolchain upgrade
+path (`docs/guide/upgrade-project.md`). The alias rewrite is unchanged in
+shape: every `npm:@voidzero-dev/vite-plus-core@1.x` spec in dependencies,
+`overrides`, `resolutions`, pnpm and Bun catalogs, and `pnpm-workspace.yaml`
+becomes `npm:@voidzero-dev/vite-plus-core@`. The existing
+`isProtocolPinnedSpec` rules keep `file:`, `link:`, and `workspace:` pins.
+
+Peer rules change only for pnpm:
+
+- `ensurePnpmPeerDependencyRules` in `vite-plus-bootstrap.ts`,
+  `rewritePnpmWorkspaceYaml` in `catalog.ts`, and the writers in
+  `orchestrators.ts` and `catalog.ts` stop adding `vite` to `allowAny` and
+  `allowedVersions` when the target core version is a stable encoded version
+  (major 8 or higher, no prerelease identifier). They remove an existing
+  `vite` entry from both maps. They delete an empty `peerDependencyRules`
+  object or YAML map. Other entries stay, including `vitest`.
+- The writers cannot tell whether an earlier migration or the user wrote a
+  `vite` entry, so they remove every `vite` entry. The only purpose of that
+  entry is to accept the `1.x` alias. `vp migrate` prints one line that names
+  the removed rule, and `docs/guide/migrate-rules.md` describes the removal.
+- When the target core version is not a stable encoded version (a preview
+  `0.0.0-commit.` or a Vite+ prerelease such as `8.4.0-vp.0`), the
+  writers keep the current behavior and write the `vite` rule.
+- `pnpmPeerDependencyRulesSatisfyVitePlus` reports a project as pending when
+  a `vite` entry exists and the target core is a stable encoded version, or
+  when the entry is missing and the target core is not.
+
+npm, Yarn, and Bun have no peer suppression to remove. Their alias handling
+is unchanged: npm keeps the direct dependency and `overrides.vite` on the same
+spec (`EOVERRIDE` rule), `npm-reinstall.ts` keeps moving stale `vite`
+installs aside by package name, Yarn keeps `resolutions.vite`, and Bun keeps
+the mirrored direct `vite` dependency.
+
+The final install step refreshes lockfiles. Every package manager sees the
+alias target version change from `1.x` to `8.x` and re-resolves it; no
+lockfile edit is needed beyond the existing npm stale-install handling.
+
+After migration, a plugin with an incompatible range (`vite: ^7.0.0`) produces
+a peer warning for the first time. This is the intended result. The migrate
+rules document must say so.
+
+### Downgrade
+
+A project on core `8.3.500` can move back to `vite-plus@1.4.0` by running
+that CLI's `vp migrate`. The older CLI rewrites the alias to
+`npm:@voidzero-dev/vite-plus-core@1.4.0` and re-adds the pnpm `vite` peer
+rule, because its logic is self-contained. Its `resolveCore` check compares
+the core version with its own version, so it reports a mismatch until the
+alias is realigned. The newer CLI reports the same for a project still on
+`1.4.0`: "Expected `@voidzero-dev/vite-plus-core@8.3.500`, found `1.4.0`.
+Run `vp migrate`." Exact pins make the registry ordering irrelevant for the
+downgrade.
+
+### Fixtures and documentation
+
+Snapshot fixtures under `crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/`
+that record `peerDependencyRules.allowAny: [vite, vitest]` or the alias
+version need re-recording with `UPDATE_SNAPSHOTS=1`. The redaction in
+`crates/vp_cli_snapshots/tests/cli_snapshots/redact.rs` already masks
+`@voidzero-dev/vite-plus-core@` with a prerelease-aware pattern, so
+local-flavor snapshots do not depend on the chosen encoding.
+
+## Alternatives
+
+### Core major = Vite major, minor and patch from `vite-plus`
+
+Simplest for the pipeline: one `sed` with a different first component. It
+fails minor ranges in both directions, as shown in the comparison table. The
+release dates in this repository already show the drift.
+
+### Plain release counter in the patch
+
+Correct for minor ranges and easier to read (`8.3.7`). It misreports patch
+floors: `>=8.3.2` fails against `8.3.0` although the bundled Vite is `8.3.5`.
+The encoded form keeps patch floors correct up to the bundled patch.
+
+The encoded form does not make every core version look different from a Vite
+version. On Vite patch 0, the core patch is `n` alone (`8.4.0`, `8.4.1`,
+...), and core `8.4.1` looks like Vite `8.4.1`. Decoding still gives the
+correct Vite version (`floor(1 / 100) = 0`). Peer checks stay in the residual
+error class of the selected scheme: `>=8.4.1` passes against core `8.4.1`.
+
+### Exact Vite version with a prerelease tag or build metadata
+
+Fails npm peer checks and cannot publish two Vite+ releases on one Vite
+patch. See the comparison.
+
+### Publish core only when the bundled Vite changes
+
+Core would use the exact Vite version. Core also bundles Rolldown, tsdown,
+and the Vite+ build of the Vite source, so a Vite+ release that changes any of
+these without a Vite change could not publish a new core.
+
+### Keep the version and ask consumers to widen peer ranges
+
+Plugins cannot know about a `1.x` alias target. The npm warning comes from
+`vite-plus`'s own dependency tree, so no consumer change removes it.
+
+### Put the bundled Vite version in `peerDependenciesMeta` or a custom field
+
+Package managers do not read a custom field for peer resolution. Only the
+manifest `version` takes part in the check.
+
+## Risks
+
+- Confusion with upstream Vite. `npm ls vite` prints
+  `vite@npm:@voidzero-dev/vite-plus-core@8.3.500`, and readers may take
+  `8.3.500` for a Vite version. On Vite patch 0, the core version (`8.4.1`)
+  looks exactly like a Vite version. The decoding rule is one division, and
+  `vp toolchain` prints the real Vite version. Documentation must show both.
+- Bundled Vite downgrade. If Vite+ goes back to an older Vite version, the
+  core version goes down, for example from `8.4.0` to `8.3.501`. The counter
+  rules still give a unique version, and exact pins make the lower version
+  install correctly. `release.yml` publishes core with `--tag latest`. How
+  npm sets `latest` when the published version is lower than the current
+  `latest` is unverified. The dist-tag check after publish (see Release
+  pipeline changes) makes a wrong tag visible.
+- Registry ordering. `8.3.500` sorts above every published `1.x` version, so
+  `latest` moves forward as usual and a range on core would jump majors.
+  Vite+ documents exact pins only. The stale `alpha` and `test` dist-tags
+  point at `0.x` versions and can be removed or left alone.
+- Peer warnings appear for real incompatibilities after migration. Projects
+  that relied on the broad rule to hide a `^7.0.0` plugin see a warning or,
+  with `strict-peer-dependencies`, an install failure. The migrate output
+  should name the change.
+- Vite+ prereleases still warn in npm: `8.4.0-vp.0` does not satisfy
+  `^8.0.0`. Accepted; see Prereleases.
+- Preview builds still warn in npm. The bridge forces `0.0.0-commit.`,
+  and the release-manager skill already lists this class of artifact as a
+  non-blocker. Migration keeps the pnpm rule for preview cores. Thus preview
+  builds cannot show the new peer behavior, and the preview check in
+  `.claude/skills/test-pkg-pr-new-migrate/` does not test it. Verification
+  before a release uses the local registry with the `n = 99` local version
+  (see Local and CI builds).
+- Tools that read the `vite` version. Vite's `version` export is rewritten in
+  `packages/core/build.ts` to import `../../package.json` relative to Vite's
+  `src/node/constants.ts`, which is Vite's own manifest, so the export keeps
+  the real Vite version. This was checked by reading the build script; the
+  built output was not inspected in this worktree. Code that reads
+  `node_modules/vite/package.json` directly, such as
+  `readInstalledRawViteVersion` in `vite-plus-bootstrap.ts`, keys on
+  `name === '@voidzero-dev/vite-plus-core'` and reads `bundledVersions.vite`.
+  Third-party code that reads `version` from that file now sees `8.3.500`
+  instead of `1.4.0`, which is closer to the truth; whether any such code
+  gates features on it is unverified.
+- Binding guards. The Rolldown binding guard in core compares the installed
+  platform package version with a baked version. Today it bakes the core
+  version, which equals the CLI version. The build must bake the CLI version
+  after this change, or every release build fails the guard.
+- Counter lookup needs the registry. `prepare_release.yml` already needs the
+  network for `cargo check`. A registry failure must stop the job with a
+  clear error rather than guess `n = 0`.
+- Pipelines that pass one `VERSION` for every package. The list in Release
+  pipeline changes covers the files found by searching for
+  `vite-plus-core`; a missed `${VERSION}` reference would publish or wait for
+  a core version that does not exist. `wait-for-npm-packages.ts` then fails
+  the job, so the error is visible.
+
+## Other aliased packages
+
+Only `vite` is aliased in user projects. `vitest` is pinned to its real
+upstream version, so peer checks against it are accurate. Rolldown and tsdown
+are bundled into core and exposed as `vite/rolldown` and `vite/pack`; they are
+not aliased, and consumers do not declare peers on them through Vite+. The
+removed `@voidzero-dev/vite-plus-test` alias no longer exists. No other
+package has the same problem, and none is in scope.
+
+## Decisions from review
+
+- Local and CI builds use the reserved `n = 99`, and the release counter stops
+  at 98 (see Local and CI builds).
+- Vite+ prereleases use the `vp.` identifier instead of a copy of the
+  `vite-plus` prerelease identifiers (see Prereleases and new Vite majors).
+- The `vitest` peer rule is removed in a follow-up with its own fixture
+  updates. `catalog.ts` already removes it when the project does not use
+  Vitest. The follow-up covers projects that use Vitest.
+- The counter comes from a registry lookup in `prepare_release.yml`, not from
+  a committed counter. The committed manifest only has to encode the bundled
+  Vite version.
+
+## Open questions
+
+1. Whether a Vite major upgrade is a `vite-plus` major release.
+   Recommendation: yes, decided in the release policy, not here.