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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "npm-workspace",
"workspaces": ["packages/*"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "unrelated-parent",
"devDependencies": {
"vitest": "npm:@voidzero-dev/vite-plus-test@0.1.24"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "pnpm-workspace"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
packages:
- .
metadata: &metadata
self: *metadata
example: npm:@voidzero-dev/vite-plus-test@0.1.24
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[[case]]
name = "config_stale_vitest_alias_boundaries"
vp = ["local", "global"]
env = { npm_lifecycle_event = "prepare" }
steps = [
{ argv = ["vp", "config", "--no-hooks", "--no-agent"], cwd = "standalone", comment = "Ignore metadata and unrelated parent package settings", continue-on-failure = true },
{ argv = ["vp", "config", "--no-hooks", "--no-agent"], cwd = "npm-workspace", comment = "Stop at the npm workspace root", continue-on-failure = true },
{ argv = ["vp", "config", "--no-hooks", "--no-agent"], cwd = "pnpm-workspace", comment = "Stop at the pnpm workspace root and ignore cyclic metadata", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# config_stale_vitest_alias_boundaries

## `cd standalone && vp config --no-hooks --no-agent`

Ignore metadata and unrelated parent package settings

```
```

## `cd npm-workspace && vp config --no-hooks --no-agent`

Stop at the npm workspace root

```
```

## `cd pnpm-workspace && vp config --no-hooks --no-agent`

Stop at the pnpm workspace root and ignore cyclic metadata

```
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# config_stale_vitest_alias_boundaries

## `cd standalone && vp config --no-hooks --no-agent`

Ignore metadata and unrelated parent package settings

```
```

## `cd npm-workspace && vp config --no-hooks --no-agent`

Stop at the npm workspace root

```
```

## `cd pnpm-workspace && vp config --no-hooks --no-agent`

Stop at the pnpm workspace root and ignore cyclic metadata

```
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "standalone",
"description": "npm:@voidzero-dev/vite-plus-test@0.1.24"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "migration-stale-vitest-alias-startup",
"scripts": {
"prepare": "vp config"
},
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:",
"vitest": "catalog:"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "11.9.0",
"onFail": "download"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
packages:
- .

catalog:
vite: npm:@voidzero-dev/vite-plus-core@0.3.0
vite-plus: 0.3.0
vitest: npm:@voidzero-dev/vite-plus-test@0.1.24

overrides:
vite: 'catalog:'
vitest: 'catalog:'
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';

const require = createRequire(import.meta.url);
const sourcePackageDir = path.dirname(require.resolve('vite-plus/package.json'));
const localPackageDir = path.join('node_modules', 'vite-plus');

fs.mkdirSync('node_modules', { recursive: true });
fs.cpSync(sourcePackageDir, localPackageDir, { recursive: true, dereference: true });

const fakeVitestDir = path.join('node_modules', 'vitest');
fs.mkdirSync(fakeVitestDir, { recursive: true });
fs.writeFileSync(
path.join(fakeVitestDir, 'package.json'),
JSON.stringify({
name: 'vitest',
version: '0.1.24',
type: 'module',
exports: {
'./config': './config.js',
'./package.json': './package.json',
},
}),
);
fs.writeFileSync(
path.join(fakeVitestDir, 'config.js'),
"throw new Error('stale Vitest alias was loaded before command dispatch');\n",
);

// This file only prepares node_modules. Remove the staged copy so migration's
// source-import pass measures the project fixture rather than its test harness.
fs.rmSync(new URL(import.meta.url));
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[case]]
name = "migration_stale_vitest_alias_startup"
vp = "global"
link-node-modules = true
steps = [
{ argv = ["node", "setup-local.mjs"], snapshot = false, continue-on-failure = true },
{ argv = ["vp", "config", "--no-hooks", "--no-agent"], envs = [["npm_lifecycle_event", "prepare"]], comment = "prepare should report the stale alias instead of loading its native binding", continue-on-failure = true },
{ argv = ["vp", "migrate", "--no-interactive"], envs = [["VP_SKIP_INSTALL", "1"]], comment = "migrate should start without loading the stale Vitest alias", continue-on-failure = true },
{ argv = ["vpt", "print-file", "package.json"], comment = "the stale Vitest dependency should be removed", continue-on-failure = true },
{ argv = ["vpt", "print-file", "pnpm-workspace.yaml"], comment = "the stale catalog alias and override should be removed", continue-on-failure = true },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# migration_stale_vitest_alias_startup

## `node setup-local.mjs`


## `npm_lifecycle_event=prepare vp config --no-hooks --no-agent`

prepare should report the stale alias instead of loading its native binding

**Exit code:** 1

```
error: Found a stale Vitest alias in pnpm-workspace.yaml that points to the removed `@voidzero-dev/vite-plus-test` package. Run `vp migrate` to update the project before installing dependencies.
```

## `VP_SKIP_INSTALL=1 vp migrate --no-interactive`

migrate should start without loading the stale Vitest alias

```
VITE+ - The Unified Toolchain for the Web

◇ Updated . to Vite+ <version>
• Node <version> pnpm <version>
• Dependencies:
vite → <version>
• Package manager settings configured
```

## `vpt print-file package.json`

the stale Vitest dependency should be removed

```
{
"name": "migration-stale-vitest-alias-startup",
"scripts": {
"prepare": "vp config"
},
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "<version>",
"onFail": "download"
}
}
}
```

## `vpt print-file pnpm-workspace.yaml`

the stale catalog alias and override should be removed

```
packages:
- .

catalog:
vite: npm:@voidzero-dev/vite-plus-core@<version>
vite-plus: <version>

overrides:
vite@*: 'catalog:'
peerDependencyRules:
allowAny:
- vite
allowedVersions:
vite: '*'
```
4 changes: 3 additions & 1 deletion packages/cli/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { fmt } from './resolve-fmt.ts';
import { lint } from './resolve-lint.ts';
import { pack } from './resolve-pack.ts';
import { test } from './resolve-test.ts';
import { resolveUniversalViteConfig } from './resolve-vite-config.ts';
import { vite } from './resolve-vite.ts';
import { accent, errorMsg, log } from './utils/terminal.ts';

Expand Down Expand Up @@ -130,6 +129,9 @@ if (maybePrintCommandHelp(args)) {
} else {
// All other commands — delegate to Rust core via NAPI binding
try {
// This module imports `vitest/config` through define-config. Load it here
// so `migrate` and `config` can handle stale aliases before Vitest loads.
const { resolveUniversalViteConfig } = await import('./resolve-vite-config.js');
const initInspection = inspectInitCommand(command, args.slice(1));
if (
initInspection.handled &&
Expand Down
14 changes: 12 additions & 2 deletions packages/cli/src/config/bin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import { join, relative } from 'node:path';

import { parseConfigArgs } from '../../binding/index.js';
import { updateExistingAgentInstructions } from '../utils/agent.ts';
import { unwrapCliParseOutcome } from '../utils/cli-parse.ts';
import { findLegacyVitestAliasConfig } from '../utils/legacy-vitest-alias.ts';
import { defaultInteractive, promptGitHooks } from '../utils/prompts.ts';
import { log } from '../utils/terminal.ts';
import { errorMsg, log } from '../utils/terminal.ts';
import {
install,
isGitHooksEnvDisabled,
Expand All @@ -23,6 +24,15 @@ async function main() {
const isLifecycleScript = lifecycleEvent === 'prepare' || lifecycleEvent === 'postinstall';
const root = process.cwd();

const staleVitestAliasConfig = findLegacyVitestAliasConfig(root);
if (staleVitestAliasConfig) {
const relativeConfigPath = relative(root, staleVitestAliasConfig);
errorMsg(
`Found a stale Vitest alias in ${relativeConfigPath} that points to the removed \`@voidzero-dev/vite-plus-test\` package. Run \`vp migrate\` to update the project before installing dependencies.`,
);
process.exit(1);
}

// --- Step 1: Hooks setup ---
// Prefer CLI flag, then last-used dir from local git config, then default.
// Check environment opt-outs before the Git-backed location lookup.
Expand Down
Loading
Loading