|
| 1 | +# Migration Rules |
| 2 | + |
| 3 | +This guide explains how `vp migrate` updates dependencies, source imports, and |
| 4 | +package-manager configuration in existing Vite+ projects. See the |
| 5 | +[migration guide](./migrate.md) for the complete command overview. |
| 6 | + |
| 7 | +## Before You Migrate |
| 8 | + |
| 9 | +1. Run `vp upgrade` before migrating an existing Vite+ project. A stale local |
| 10 | + CLI does not contain the new migration rules; migration delegates to the |
| 11 | + global CLI when the local version is older. |
| 12 | +2. Upgrade the project to Vite 8+ and Vitest 4.1+ when necessary. |
| 13 | +3. Run `vp migrate` from the workspace root. Use `--no-interactive` in |
| 14 | + automated environments. |
| 15 | +4. Review every changed manifest, package-manager config, source rewrite, and |
| 16 | + generated lockfile. |
| 17 | +5. Validate with `vp install`, `vp check`, `vp test`, and `vp build`. |
| 18 | + |
| 19 | +Running the migration again after a successful migration should not produce |
| 20 | +another diff. |
| 21 | + |
| 22 | +## Dependency Versions |
| 23 | + |
| 24 | +- `vite-plus` is pinned to the concrete version of the CLI running the |
| 25 | + migration, not the `latest` dist-tag. |
| 26 | +- The `vite` alias must target `@voidzero-dev/vite-plus-core` from the same |
| 27 | + Vite+ release. |
| 28 | +- A catalog-backed manifest may contain `catalog:` or an existing named catalog |
| 29 | + reference. The referenced catalog value must still be updated to the concrete |
| 30 | + toolchain target. |
| 31 | +- Preserve deliberate protocol pins such as `workspace:`, `file:`, `link:`, |
| 32 | + `npm:`, `github:`, Git URLs, and HTTP URLs. |
| 33 | +- Reconcile every workspace package, not only the root manifest. Shared |
| 34 | + overrides and catalogs stay at the workspace root; direct peer providers |
| 35 | + belong in each package that needs them. |
| 36 | + |
| 37 | +## Dependency Changes |
| 38 | + |
| 39 | +| Dependency | Migration rule | |
| 40 | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 41 | +| `vite-plus` | Add it where the package is migrated. Re-pin plain ranges to the current concrete target, directly or through a catalog. Preserve deliberate protocol pins. | |
| 42 | +| `vite` | Keep or add a real dependency edge where peer resolution requires one, and rewrite that edge plus the shared override/resolution to the matching `@voidzero-dev/vite-plus-core` target. An override rewrites an edge; it does not create one. | |
| 43 | +| `vitest` | Remove it in the common node-mode case because `vite-plus` provides it transitively. Keep or add an exact bundled version only in packages with direct Vitest requirements. | |
| 44 | +| `@vitest/*` | Align lockstep packages that the project directly lists to the bundled Vitest version. Prefer the package's existing catalog reference when its catalog owns that package; otherwise write the concrete version. | |
| 45 | +| `@voidzero-dev/vite-plus-test` | Remove all dependency, override, resolution, and catalog aliases. Rewrite imports to the current `vite-plus/test*` surface. | |
| 46 | + |
| 47 | +### Vite and Overrides |
| 48 | + |
| 49 | +Package-manager overrides do not synthesize dependency edges. This matters most |
| 50 | +with pnpm: Vitest has a required `vite` peer, and pnpm can auto-install upstream |
| 51 | +Vite when a package that depends on `vite-plus` has no direct `vite` edge. That |
| 52 | +creates separate Vite+, Vite, and Vitest peer contexts. Each affected pnpm |
| 53 | +workspace package must therefore declare `vite`; the workspace override then |
| 54 | +redirects that edge to Vite+ core. |
| 55 | + |
| 56 | +Do not remove a direct `vite` declaration merely because a root override exists. |
| 57 | +Normalize existing plain or stale aliases while retaining named catalog |
| 58 | +references. A real edge is also required for Bun's peer resolver, and npm |
| 59 | +browser-provider layouts may need a top-level edge so nested Vitest packages can |
| 60 | +resolve `vite`. After migration, pnpm users should verify that each affected |
| 61 | +workspace package has the required direct edge. |
| 62 | + |
| 63 | +### When Vitest Is Directly Required |
| 64 | + |
| 65 | +Keep or add package-local `vitest` at the exact bundled version when any of the |
| 66 | +following is true: |
| 67 | + |
| 68 | +- an installed dependency has a non-optional `vitest` peer, whether exact or a |
| 69 | + range; |
| 70 | +- the package uses Vitest browser mode or an opt-in browser provider; |
| 71 | +- source or TypeScript configuration retains an upstream `vitest` reference; |
| 72 | +- the package declares `@nuxt/test-utils`; or |
| 73 | +- dependency metadata is unavailable and an existing direct `vitest` might be |
| 74 | + satisfying an unknown required peer. |
| 75 | + |
| 76 | +`vp migrate` checks installed peer metadata, so integrations such as |
| 77 | +`vite-plugin-gherkin` are handled even though their names do not contain |
| 78 | +`vitest`. |
| 79 | + |
| 80 | +When a package directly requires Vitest: |
| 81 | + |
| 82 | +- add `vitest` to that package, not indiscriminately to every workspace package; |
| 83 | +- use the existing catalog reference when supported, otherwise use the exact |
| 84 | + bundled version; and |
| 85 | +- keep a matching workspace override or resolution so the graph uses one |
| 86 | + Vitest version. |
| 87 | + |
| 88 | +A peer declaration alone does not install Vitest. If a surviving |
| 89 | +`peerDependencies.vitest` uses a catalog entry that migration will remove, |
| 90 | +resolve it to the public peer range first. |
| 91 | + |
| 92 | +### Vitest Ecosystem Packages |
| 93 | + |
| 94 | +Official current `@vitest/*` packages generally publish in lockstep with |
| 95 | +Vitest. Align packages the project directly installs, including |
| 96 | +`@vitest/coverage-v8`, `@vitest/coverage-istanbul`, `@vitest/ui`, and |
| 97 | +`@vitest/web-worker`. |
| 98 | + |
| 99 | +Catalog handling is package-specific: |
| 100 | + |
| 101 | +- preserve `catalog:` and named `catalog:<name>` dependency references when the |
| 102 | + corresponding catalog already defines that package; |
| 103 | +- update that catalog entry to the bundled Vitest version; and |
| 104 | +- use the concrete bundled version when no catalog owns the package. |
| 105 | + |
| 106 | +Do not align independently versioned or obsolete packages: |
| 107 | + |
| 108 | +- `@vitest/eslint-plugin` has its own version line; |
| 109 | +- `@vitest/coverage-c8` stopped at an older release and has no Vitest 4 version; |
| 110 | + and |
| 111 | +- third-party `vitest-*` integrations keep their own compatible package |
| 112 | + versions, although their required Vitest peer may require direct provisioning. |
| 113 | + |
| 114 | +The base `@vitest/browser` runtime and `@vitest/browser-preview` are bundled by |
| 115 | +Vite+ and should be removed as direct dependencies. The Playwright and |
| 116 | +WebdriverIO providers remain opt-in: keep or add the provider at the bundled |
| 117 | +Vitest version and ensure its `playwright` or `webdriverio` peer is installed. |
| 118 | + |
| 119 | +Object-valued nested npm and Bun overrides are preserved because they are |
| 120 | +user-defined scopes rather than scalar version pins. |
| 121 | + |
| 122 | +## Source Rewrite Rules |
| 123 | + |
| 124 | +- Rewrite ordinary `vitest` and `vitest/*` imports to `vite-plus/test*`. |
| 125 | +- Rewrite scoped browser imports to the corresponding |
| 126 | + `vite-plus/test/browser*` exports and provision opt-in providers when needed. |
| 127 | +- Leave existing `vite-plus/test*` imports unchanged. |
| 128 | +- Do not rewrite `declare module 'vitest'` or |
| 129 | + `declare module '@vitest/browser*'`. Module augmentation must retain the |
| 130 | + upstream module identity. |
| 131 | +- Retained references such as `compilerOptions.types`, `require.resolve`, |
| 132 | + `import.meta.resolve`, and `vitest/package.json` require package-local Vitest. |
| 133 | +- In a package that declares `@nuxt/test-utils`, preserve every `vitest` and |
| 134 | + `vitest/*` module specifier package-wide. Its transform requires the upstream |
| 135 | + identity and can otherwise inject a duplicate `vi` import. This exception |
| 136 | + does not apply to sibling packages or scoped `@vitest/browser*` imports. |
| 137 | + |
| 138 | +The `prefer-vite-plus-imports` lint rule follows the same Nuxt exception, so |
| 139 | +lint autofix preserves these imports. |
| 140 | + |
| 141 | +## Package-Manager Rules |
| 142 | + |
| 143 | +### pnpm |
| 144 | + |
| 145 | +- pnpm 10.6.2+ uses `pnpm-workspace.yaml` as the single source for supported |
| 146 | + root settings. Migration moves recognized `package.json#pnpm` fields there, |
| 147 | + including overrides, peer rules, patch settings, package extensions, |
| 148 | + architecture and build policy, audit/update configuration, and configuration |
| 149 | + dependencies. It removes the `pnpm` object when it becomes empty and preserves |
| 150 | + unknown keys that may belong to other tooling. |
| 151 | +- Before pnpm 10.6.2, migration retains these settings in |
| 152 | + `package.json#pnpm`. General workspace-setting support started in pnpm 10.5.0, |
| 153 | + but overrides required 10.5.1 and `peerDependencyRules` required 10.6.2. pnpm |
| 154 | + 11 no longer reads the legacy package.json settings. |
| 155 | +- Migration keeps dependency references, default and named catalogs, overrides, |
| 156 | + and `peerDependencyRules` consistent. |
| 157 | +- Each package whose `vite-plus`/Vitest peer context would otherwise install |
| 158 | + upstream Vite needs a direct `vite` edge. |
| 159 | +- Unrelated selector-shaped and object-valued overrides are preserved. |
| 160 | + |
| 161 | +### npm |
| 162 | + |
| 163 | +- Migration normalizes direct aliases before adding the matching override so |
| 164 | + npm does not fail with `EOVERRIDE`. |
| 165 | +- When changing a real Vite installation to the core alias, remove stale Vite |
| 166 | + install and lockfile state before reinstalling. |
| 167 | +- Add a top-level `vite` edge for opt-in browser-provider layouts when nested |
| 168 | + Vitest packages otherwise cannot resolve it. |
| 169 | + |
| 170 | +### Yarn |
| 171 | + |
| 172 | +- Vite+ does not support Plug'n'Play. Detect explicit and implicit PnP before |
| 173 | + migration and convert the project to `nodeLinker: node-modules`. Preserve all |
| 174 | + unrelated `.yarnrc.yml` settings. `--no-interactive` accepts the conversion; |
| 175 | + a process-level `YARN_NODE_LINKER=pnp` must be fixed by the caller. |
| 176 | +- Catalog references and user hoisting settings are preserved. |
| 177 | +- Migration avoids split Vitest copies under workspace hoisting isolation. It |
| 178 | + applies a package-level fix where possible and warns when the isolation |
| 179 | + cannot be changed safely. |
| 180 | + |
| 181 | +### Bun |
| 182 | + |
| 183 | +- Preserve existing top-level or workspace catalog locations and named catalog |
| 184 | + references. |
| 185 | +- Mirror the core alias as a direct `vite` dependency so Bun sees the peer |
| 186 | + provider before applying overrides. |
| 187 | +- Configure missing-peer suppression in `bunfig.toml` when needed, but do not |
| 188 | + overwrite an explicit user `peer` setting. |
| 189 | + |
| 190 | +After updating the manifests and package-manager configuration, migration |
| 191 | +reinstalls dependencies once to refresh the lockfile. If installation fails, |
| 192 | +migration reports the error and exits with a nonzero status. |
0 commit comments