chore: remove tools/ai-migrations generated by nx migrate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
maulanasdqn
2026-03-31 16:29:00 +07:00
co-authored by Claude Opus 4.6
parent 8439c5d5e0
commit 629d609792
2 changed files with 0 additions and 1570 deletions
-845
View File
@@ -1,845 +0,0 @@
# Next.js 16 Migration Instructions for LLM
## Overview
These instructions guide you through migrating an Nx workspace containing Next.js projects from Next.js 15 to Next.js 16. Work systematically through each breaking change category.
## Pre-Migration Checklist
1. **Identify all Next.js projects**:
```bash
nx show projects --with-target build | xargs -I {} nx show project {} --json | jq -r 'select(.targets.build.executor | contains("next")) | .name'
```
Or search for Next.js configuration files:
```bash
find . -name "next.config.*" -not -path "*/node_modules/*"
```
2. **Update packages**:
```bash
npm install next@latest react@latest react-dom@latest
npm install -D @types/react @types/react-dom # if using TypeScript
```
3. **Verify minimum requirements**:
- Node.js 20.9+ (Node.js 18 is no longer supported)
- TypeScript 5.1.0+
- Browser support: Chrome 111+, Edge 111+, Firefox 111+, Safari 16.4+
## Migration Steps by Category
### 1. Async Request APIs (Major Breaking Change)
This is the most impactful change in Next.js 16. All dynamic request APIs are now asynchronous.
**Search Patterns**:
- `cookies()` usage in server components
- `headers()` usage in server components
- `draftMode()` usage
- `params` in page, layout, route handlers, and metadata files
- `searchParams` in page components
#### 1.1 Page Components with params
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export default function Page({ params }) {
const { slug } = params;
return <h1>{slug}</h1>;
}
// AFTER (Next.js 16)
export default async function Page(props) {
const { slug } = await props.params;
return <h1>{slug}</h1>;
}
```
**Action Items**:
- [ ] Make all page components that use `params` async
- [ ] Add `await` before accessing `props.params`
- [ ] Update TypeScript types if applicable
#### 1.2 Page Components with searchParams
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export default function Page({ searchParams }) {
const query = searchParams.q;
return <Results query={query} />;
}
// AFTER (Next.js 16)
export default async function Page(props) {
const searchParams = await props.searchParams;
const query = searchParams.q;
return <Results query={query} />;
}
```
**Action Items**:
- [ ] Make all page components that use `searchParams` async
- [ ] Add `await` before accessing `props.searchParams`
#### 1.3 Layout Components with params
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export default function Layout({ children, params }) {
const { locale } = params;
return <div data-locale={locale}>{children}</div>;
}
// AFTER (Next.js 16)
export default async function Layout(props) {
const { locale } = await props.params;
return <div data-locale={locale}>{props.children}</div>;
}
```
#### 1.4 Route Handlers
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export async function GET(request, { params }) {
const { id } = params;
return Response.json({ id });
}
// AFTER (Next.js 16)
export async function GET(request, props) {
const { id } = await props.params;
return Response.json({ id });
}
```
#### 1.5 cookies() and headers()
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
import { cookies, headers } from 'next/headers';
export default function Page() {
const cookieStore = cookies();
const headersList = headers();
const theme = cookieStore.get('theme');
const userAgent = headersList.get('user-agent');
return <div>...</div>;
}
// AFTER (Next.js 16)
import { cookies, headers } from 'next/headers';
export default async function Page() {
const cookieStore = await cookies();
const headersList = await headers();
const theme = cookieStore.get('theme');
const userAgent = headersList.get('user-agent');
return <div>...</div>;
}
```
#### 1.6 draftMode()
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
import { draftMode } from 'next/headers';
export default function Page() {
const { isEnabled } = draftMode();
return <div>{isEnabled ? 'Draft' : 'Published'}</div>;
}
// AFTER (Next.js 16)
import { draftMode } from 'next/headers';
export default async function Page() {
const { isEnabled } = await draftMode();
return <div>{isEnabled ? 'Draft' : 'Published'}</div>;
}
```
#### 1.7 generateMetadata with params
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export async function generateMetadata({ params }) {
const { slug } = params;
return { title: slug };
}
// AFTER (Next.js 16)
export async function generateMetadata(props) {
const { slug } = await props.params;
return { title: slug };
}
```
#### 1.8 Automated Migration
Run the Next.js codemod for automated migration:
```bash
npx @next/codemod@canary upgrade latest
```
Generate type helpers for safer migrations (Next.js 15.5+):
```bash
npx next typegen
```
This generates `PageProps`, `LayoutProps`, and `RouteContext` helpers.
### 2. Image Generation Functions
**Search Pattern**: `generateImageMetadata`, `default function Image` in opengraph-image or twitter-image files
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export function generateImageMetadata({ params }) {
const { slug } = params;
return [{ id: '1' }];
}
export default function Image({ params, id }) {
const slug = params.slug;
return new ImageResponse(/* ... */);
}
// AFTER (Next.js 16)
export async function generateImageMetadata({ params }) {
const { slug } = await params;
return [{ id: '1' }];
}
export default async function Image({ params, id }) {
const { slug } = await params;
const imageId = await id;
return new ImageResponse(/* ... */);
}
```
**Action Items**:
- [ ] Make `generateImageMetadata` functions async
- [ ] Make Image components async
- [ ] Add `await` for both `params` and `id` access
### 3. Sitemap Generation
**Search Pattern**: `sitemap` functions with `id` parameter
**Changes Required**:
```tsx
// BEFORE (Next.js 15)
export default async function sitemap({ id }) {
const start = id * 50000;
// ...
}
// AFTER (Next.js 16)
export default async function sitemap({ id }) {
const resolvedId = await id;
const start = resolvedId * 50000;
// ...
}
```
### 4. Turbopack Configuration
Turbopack is now the default bundler for development.
**Search Pattern**: `--turbo` or `--turbopack` flags in package.json scripts, `turbopack` in next.config
#### 4.1 Remove Explicit Turbopack Flags
```json
// BEFORE (Next.js 15)
{
"scripts": {
"dev": "next dev --turbo"
}
}
// AFTER (Next.js 16) - Turbopack is default
{
"scripts": {
"dev": "next dev"
}
}
```
#### 4.2 Opt Out to Webpack (if needed)
```json
{
"scripts": {
"build": "next build --webpack"
}
}
```
#### 4.3 Move Turbopack Config Out of Experimental
```ts
// BEFORE (Next.js 15)
const nextConfig = {
experimental: {
turbopack: {
/* options */
},
},
};
// AFTER (Next.js 16)
const nextConfig = {
turbopack: {
/* options */
},
};
```
#### 4.4 Update Sass Imports (Turbopack Specific)
```scss
/* BEFORE */
@import '~bootstrap/dist/css/bootstrap.min.css';
/* AFTER - Remove tilde prefix */
@import 'bootstrap/dist/css/bootstrap.min.css';
```
**Action Items**:
- [ ] Remove `--turbo` and `--turbopack` flags from scripts
- [ ] Move `turbopack` config from `experimental` to root level
- [ ] Remove tilde (`~`) prefix from Sass imports
- [ ] Add `--webpack` flag if Webpack is required
### 5. Middleware to Proxy Rename
**Search Pattern**: `middleware.ts` or `middleware.js` files
**Changes Required**:
```bash
# Rename the file
mv middleware.ts proxy.ts
```
```ts
// BEFORE (middleware.ts)
export function middleware(request) {
// ...
}
// AFTER (proxy.ts)
export function proxy(request) {
// ...
}
```
**Config Updates**:
```js
// BEFORE
{
skipMiddlewareUrlNormalize: true;
}
// AFTER
{
skipProxyUrlNormalize: true;
}
```
**Important**: The Edge runtime is no longer supported in `proxy`. It now uses Node.js runtime.
**Action Items**:
- [ ] Rename `middleware.ts/js` to `proxy.ts/js`
- [ ] Rename exported function from `middleware` to `proxy`
- [ ] Update config option names
- [ ] Remove Edge runtime usage from proxy files
### 6. Parallel Routes default.js Requirement
**Search Pattern**: Directories starting with `@` in the app folder (parallel route slots)
All parallel route slots now require an explicit `default.js` file.
**Changes Required**:
```tsx
// Create app/@modal/default.tsx for each parallel route slot
import { notFound } from 'next/navigation';
export default function Default() {
notFound(); // or return null
}
```
**Action Items**:
- [ ] Find all parallel route slots (`app/@*/`)
- [ ] Create `default.tsx` in each slot that doesn't have one
### 7. Image Optimization Changes
#### 7.1 Local Images with Query Strings
```tsx
// Now requires explicit configuration
<Image src="/assets/photo?v=1" alt="Photo" width="100" height="100" />
```
```js
// next.config.js
module.exports = {
images: {
localPatterns: [
{
pathname: '/assets/**',
search: '?v=1',
},
],
},
};
```
#### 7.2 Default Value Changes
Add these to `next.config.js` if you need the old defaults:
```js
module.exports = {
images: {
// minimumCacheTTL changed from 60 to 14400 seconds
minimumCacheTTL: 60,
// Value 16 removed from default imageSizes
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
// qualities now defaults to [75] only
qualities: [50, 75, 100],
// Local IP now blocked by default
dangerouslyAllowLocalIP: true, // only for private networks
// Maximum redirects changed from unlimited to 3
maximumRedirects: 5,
},
};
```
#### 7.3 Deprecated images.domains
```js
// BEFORE - Remove this
module.exports = {
images: {
domains: ['example.com'],
},
};
// AFTER - Use remotePatterns instead
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
};
```
**Action Items**:
- [ ] Add `localPatterns` for images with query strings
- [ ] Migrate `images.domains` to `images.remotePatterns`
- [ ] Review and update default values if needed
### 8. Caching API Updates
#### 8.1 Remove unstable\_ Prefix
```ts
// BEFORE (Next.js 15)
import {
unstable_cacheLife as cacheLife,
unstable_cacheTag as cacheTag,
} from 'next/cache';
// AFTER (Next.js 16)
import { cacheLife, cacheTag } from 'next/cache';
```
#### 8.2 New Cache Functions
**revalidateTag with cacheLife profile**:
```ts
'use server';
import { revalidateTag } from 'next/cache';
export async function updateArticle(articleId: string) {
revalidateTag(`article-${articleId}`, 'max');
}
```
**updateTag (new)**:
```ts
'use server';
import { updateTag } from 'next/cache';
export async function updateUserProfile(userId: string, profile: Profile) {
await db.users.update(userId, profile);
updateTag(`user-${userId}`);
}
```
**refresh (new)**:
```ts
'use server';
import { refresh } from 'next/cache';
export async function markNotificationAsRead(notificationId: string) {
await db.notifications.markAsRead(notificationId);
refresh();
}
```
**Action Items**:
- [ ] Remove `unstable_` prefix from `cacheLife` and `cacheTag` imports
- [ ] Consider using new `updateTag` and `refresh` functions
### 9. React Compiler Support
React Compiler is now stable and supported:
```ts
// next.config.ts
const nextConfig = {
reactCompiler: true,
};
export default nextConfig;
```
Install the plugin:
```bash
npm install -D babel-plugin-react-compiler
```
**Note**: Expect higher compile times with React Compiler enabled.
### 10. Scroll Behavior Override
Next.js no longer overrides `scroll-behavior: smooth` during navigation.
To restore previous behavior:
```tsx
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html lang="en" data-scroll-behavior="smooth">
<body>{children}</body>
</html>
);
}
```
### 11. ESLint Migration
The `next lint` command has been removed. Migrate to ESLint CLI directly.
```bash
# Run migration codemod
npx @next/codemod@canary next-lint-to-eslint-cli .
```
Remove from `next.config.js`:
```js
// Remove this
{
eslint: {
}
}
```
**Action Items**:
- [ ] Run the ESLint migration codemod
- [ ] Remove `eslint` config from `next.config.js`
- [ ] Update CI scripts to use `eslint` directly instead of `next lint`
### 12. Feature Removals
#### 12.1 AMP Support Removed
- All AMP APIs have been deleted
- Remove `useAmp` hook usage
- Remove `amp` config option
- Delete AMP-specific pages
#### 12.2 Runtime Configuration Removed
```js
// BEFORE - Remove these
module.exports = {
serverRuntimeConfig: { dbUrl: process.env.DATABASE_URL },
publicRuntimeConfig: { apiUrl: '/api' },
};
```
**Migration for server-side config**:
```tsx
// Use environment variables directly
async function fetchData() {
const dbUrl = process.env.DATABASE_URL;
return await db.query(dbUrl, 'SELECT * FROM users');
}
```
**Migration for client-side config**:
```bash
# .env.local
NEXT_PUBLIC_API_URL="/api"
```
```tsx
'use client';
export default function Component() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// ...
}
```
#### 12.3 devIndicators Options Removed
Remove these from `next.config.js`:
- `appIsrStatus`
- `buildActivity`
- `buildActivityPosition`
#### 12.4 experimental.dynamicIO Renamed
```js
// BEFORE
{
experimental: {
dynamicIO: true;
}
}
// AFTER
{
cacheComponents: true;
}
```
#### 12.5 unstable_rootParams Removed
This API is removed. Await alternative API in a future minor release.
**Action Items**:
- [ ] Remove all AMP-related code
- [ ] Migrate runtime configuration to environment variables
- [ ] Remove deprecated devIndicators options
- [ ] Rename `dynamicIO` to `cacheComponents`
### 13. Development Changes
#### 13.1 Concurrent dev and build
Development now outputs to `.next/dev` (separate from build).
**Update Turbopack tracing command**:
```bash
npx next internal trace .next/dev/trace-turbopack
```
## Post-Migration Validation
### 1. Run Build Per Project
```bash
# Build each Next.js project individually
nx run PROJECT_NAME:build
```
### 2. Run Development Server
```bash
# Start dev server to verify Turbopack works
nx run PROJECT_NAME:serve
```
### 3. Run All Affected Builds
```bash
# Build all affected projects
nx affected -t build
```
### 4. Run Full Validation
```bash
# Run full CI validation
nx prepush
```
### 5. Review Migration Checklist
- [ ] All async request APIs updated
- [ ] All page/layout components using params are async
- [ ] Turbopack configuration updated
- [ ] Middleware renamed to proxy
- [ ] Parallel routes have default.js files
- [ ] Image configuration updated
- [ ] Cache imports updated (removed unstable\_ prefix)
- [ ] AMP code removed
- [ ] Runtime config migrated to env vars
- [ ] ESLint configuration migrated
- [ ] All projects build successfully
- [ ] Development servers start correctly
## Common Issues and Solutions
### Issue: "cookies() expects to be called in a synchronous context"
**Solution**: Make the function async and await `cookies()`
### Issue: "params should be awaited before accessing properties"
**Solution**: Add `await` before accessing `props.params`
### Issue: Build fails with Turbopack
**Solution**: Add `--webpack` flag to build script, then gradually address Turbopack compatibility
### Issue: Middleware not working after rename
**Solution**: Ensure both file and function are renamed from `middleware` to `proxy`
### Issue: Parallel route not rendering
**Solution**: Add `default.tsx` file to the parallel route slot
### Issue: Images with query strings not loading
**Solution**: Add `localPatterns` configuration for those images
### Issue: TypeScript errors with params types
**Solution**: Run `npx next typegen` to generate type helpers, then use `PageProps`, `LayoutProps` types
## Files to Review
Create a checklist of all files that need review:
```bash
# Find all pages with potential params usage
find . -path "*/app/*" -name "page.tsx" -o -name "page.ts" | xargs grep -l "params\|searchParams"
# Find all layouts
find . -path "*/app/*" -name "layout.tsx" -o -name "layout.ts"
# Find all route handlers
find . -path "*/app/*" -name "route.ts" -o -name "route.tsx"
# Find middleware files
find . -name "middleware.ts" -o -name "middleware.js"
# Find files using cookies/headers
rg "from 'next/headers'" --type ts --type tsx
# Find next.config files
find . -name "next.config.*" -not -path "*/node_modules/*"
# Find parallel routes
find . -path "*/app/@*" -type d
```
## Migration Strategy for Large Workspaces
1. **Migrate in phases**: Start with a small project, validate, then expand
2. **Use the codemod**: Run `npx @next/codemod@canary upgrade latest` for automated fixes
3. **Generate types**: Run `npx next typegen` for type-safe migrations
4. **Run tests frequently**: After each configuration change, run affected tests
5. **Document issues**: Keep track of project-specific issues and solutions
## Useful Commands During Migration
```bash
# Find all Next.js projects
nx show projects --with-target build
# Build specific project
nx build PROJECT_NAME
# Serve specific project
nx serve PROJECT_NAME
# Build all affected
nx affected -t build
# View project details
nx show project PROJECT_NAME --web
# Clear Nx cache if needed
nx reset
```
---
## Notes for LLM Execution
When executing this migration:
1. **Work systematically**: Complete one category before moving to the next
2. **Test after each change**: Don't batch all changes without validation
3. **Keep user informed**: Report progress through each section
4. **Handle errors promptly**: If builds fail, fix immediately before proceeding
5. **Use the codemod first**: Let `@next/codemod` handle repetitive async/await changes
6. **Prioritize breaking changes**: Focus on async APIs first as they're most impactful
7. **Create meaningful commits**: Group related changes together with clear messages
8. **Use TodoWrite tool**: Track migration progress for visibility
-725
View File
@@ -1,725 +0,0 @@
# Vitest 4.0 Migration Instructions for LLM
## Overview
These instructions guide you through migrating an Nx workspace containing multiple Vitest projects from Vitest 3.x to Vitest 4.0. Work systematically through each breaking change category.
## Pre-Migration Checklist
1. **Identify all Vitest projects**:
```bash
nx show projects --with-target test
```
2. **Locate all Vitest configuration files**:
- Search for `vitest.config.{ts,js,mjs}`
- Search for `vitest.workspace.{ts,js,mjs}`
- Check `project.json` files for inline Vitest configuration
3. **Identify affected code**:
- Test files: `**/*.{spec,test}.{ts,js,tsx,jsx}`
- Mock usage: Files using `vi.fn()`, `vi.spyOn()`, `vi.mock()`
- Coverage configuration references
## Migration Steps by Category
### 1. Configuration File Updates
#### 1.1 Coverage Configuration
**Search Pattern**: `coverage` in all `vitest.config.*` files and `project.json` test target options
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
coverage: {
all: true,
extensions: ['.ts', '.tsx'],
ignoreEmptyLines: false,
experimentalAstAwareRemapping: true,
},
},
});
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
coverage: {
// Explicitly define files to include in coverage
include: ['src/**/*.{ts,tsx}'],
// Remove: all, extensions, ignoreEmptyLines, experimentalAstAwareRemapping
},
},
});
```
**Action Items**:
- [ ] Remove `coverage.all` option
- [ ] Remove `coverage.extensions` option
- [ ] Remove `coverage.ignoreEmptyLines` option
- [ ] Remove `coverage.experimentalAstAwareRemapping` option
- [ ] Add explicit `coverage.include` patterns based on project structure
- [ ] Update any documentation referencing these options
#### 1.2 Pool Options Restructuring
**Search Pattern**: `poolOptions`, `maxThreads`, `maxForks`, `singleThread`, `singleFork` in all Vitest config files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
maxThreads: 4,
maxForks: 2,
singleThread: false,
poolOptions: {
threads: {
useAtomics: true,
},
vmThreads: {
memoryLimit: '512MB',
},
},
},
});
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
maxWorkers: 4, // Consolidates maxThreads and maxForks
isolate: true, // Replaces singleThread: false
// Remove: poolOptions, threads.useAtomics
vmMemoryLimit: '512MB', // Moved to top-level
},
});
```
**Action Items**:
- [ ] Replace `maxThreads` and `maxForks` with single `maxWorkers` option
- [ ] Replace `singleThread: true` or `singleFork: true` with `maxWorkers: 1, isolate: false`
- [ ] Move all `poolOptions.*` nested options to top-level (e.g., `poolOptions.vmThreads.memoryLimit` → `vmMemoryLimit`)
- [ ] Remove `threads.useAtomics` option
- [ ] Update CI environment variables: `VITEST_MAX_THREADS` and `VITEST_MAX_FORKS` → `VITEST_MAX_WORKERS`
#### 1.3 Workspace to Projects Rename
**Search Pattern**: `workspace` property in Vitest config files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
workspace: ['apps/*', 'libs/*'],
},
});
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
projects: ['apps/*', 'libs/*'],
},
});
```
**Action Items**:
- [ ] Rename `workspace` property to `projects` in all config files
- [ ] Remove external workspace file references (must be inline in config)
- [ ] Update `poolMatchGlobs` to use `projects` pattern matching instead
- [ ] Update `environmentMatchGlobs` to use `projects` pattern matching instead
#### 1.4 Browser Configuration
**Search Pattern**: `browser.provider`, `browser.testerScripts`, imports from `@vitest/browser`
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
browser: {
enabled: true,
provider: 'playwright', // String value
testerScripts: ['./setup.js'],
},
},
});
// Import changes
import { page } from '@vitest/browser';
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
browser: {
enabled: true,
provider: { name: 'playwright' }, // Object value
testerHtmlPath: './test-setup.html', // Renamed from testerScripts
},
},
});
// Import changes
import { page } from 'vitest/browser';
```
**Action Items**:
- [ ] Convert `browser.provider` string values to object format: `{ name: 'provider-name' }`
- [ ] Replace `browser.testerScripts` with `browser.testerHtmlPath`
- [ ] Update all imports from `@vitest/browser` to `vitest/browser`
- [ ] Remove `@vitest/browser` from dependencies if no longer needed
#### 1.5 Deprecated Configuration Options
**Search Pattern**: `deps.external`, `deps.inline`, `deps.fallbackCJS` in config files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
deps: {
external: ['some-package'],
inline: ['inline-package'],
fallbackCJS: true,
},
},
});
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
server: {
deps: {
external: ['some-package'],
inline: ['inline-package'],
fallbackCJS: true,
},
},
},
});
```
**Action Items**:
- [ ] Move `deps.*` options under `server.deps` namespace
- [ ] Remove `poolMatchGlobs` (use `projects` with conditions instead)
- [ ] Remove `environmentMatchGlobs` (use `projects` with conditions instead)
### 2. Test Code Updates
#### 2.1 Mock Function Name Changes
**Search Pattern**: `.getMockName()` calls in test files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
const mockFn = vi.fn();
expect(mockFn.getMockName()).toBe('spy'); // Old default
// ✅ AFTER (Vitest 4.0)
const mockFn = vi.fn();
expect(mockFn.getMockName()).toBe('vi.fn()'); // New default
// If you need custom names, set them explicitly
const namedMock = vi.fn().mockName('myCustomName');
expect(namedMock.getMockName()).toBe('myCustomName');
```
**Action Items**:
- [ ] Update test assertions checking default mock names from `'spy'` to `'vi.fn()'`
- [ ] Add explicit `.mockName()` calls where specific names are required
#### 2.2 Mock Invocation Call Order
**Search Pattern**: `.mock.invocationCallOrder` in test files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
const mockFn = vi.fn();
mockFn();
expect(mockFn.mock.invocationCallOrder[0]).toBe(0); // Started at 0
// ✅ AFTER (Vitest 4.0)
const mockFn = vi.fn();
mockFn();
expect(mockFn.mock.invocationCallOrder[0]).toBe(1); // Now starts at 1 (Jest-compatible)
```
**Action Items**:
- [ ] Update assertions on `invocationCallOrder` to account for 1-based indexing
- [ ] Search for off-by-one errors in call order comparisons
#### 2.3 Constructor Spies and Mocks
**Search Pattern**: `vi.spyOn` on constructors, `vi.fn()` used as constructors
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x) - Arrow function constructors might have worked
const MockConstructor = vi.fn(() => ({ value: 42 }));
new MockConstructor(); // May have worked in v3
// ✅ AFTER (Vitest 4.0) - Must use function or class
const MockConstructor = vi.fn(function () {
return { value: 42 };
});
new MockConstructor(); // Correctly supports 'new'
// Or use class syntax
class MockClass {
value = 42;
}
const MockConstructor = vi.fn(MockClass);
```
**Action Items**:
- [ ] Convert arrow function mocks used as constructors to `function` keyword or `class` syntax
- [ ] Test all constructor spies to ensure `new` keyword works correctly
- [ ] Update any mocks that expect constructor behavior
#### 2.4 RestoreAllMocks Behavior
**Search Pattern**: `vi.restoreAllMocks()` in test files
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
vi.mock('./module', () => ({ fn: vi.fn() }));
vi.restoreAllMocks(); // Would restore automocks
// ✅ AFTER (Vitest 4.0)
vi.mock('./module', () => ({ fn: vi.fn() }));
vi.restoreAllMocks(); // Only restores manual spies, NOT automocks
// To reset automocks, use:
vi.unmock('./module');
// or
vi.resetModules();
```
**Action Items**:
- [ ] Review all `vi.restoreAllMocks()` usage
- [ ] Add explicit `vi.unmock()` or `vi.resetModules()` calls for automocked modules
- [ ] Ensure test isolation is maintained after this change
#### 2.5 SpyOn Return Value Changes
**Search Pattern**: `vi.spyOn()` on already mocked functions
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
const mock = vi.fn();
const spy = vi.spyOn({ method: mock }, 'method');
// spy !== mock (created new spy)
// ✅ AFTER (Vitest 4.0)
const mock = vi.fn();
const spy = vi.spyOn({ method: mock }, 'method');
// spy === mock (returns same instance)
```
**Action Items**:
- [ ] Review code that creates spies on existing mocks
- [ ] Remove redundant spy creation if same instance is returned
- [ ] Update assertions that check spy identity
#### 2.6 Automock Behavior Changes
**Search Pattern**: `vi.mock()` with factory functions, `.mockRestore()` on automocks
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
vi.mock('./utils', () => ({
get value() {
return 42;
}, // Would call getter
}));
import { value } from './utils';
console.log(value); // Would execute getter logic
// Restore might have worked
const spy = vi.spyOn(obj, 'method');
spy.mockRestore(); // Might work on automocks
// ✅ AFTER (Vitest 4.0)
vi.mock('./utils', () => ({
get value() {
return 42;
},
}));
import { value } from './utils';
console.log(value); // Returns undefined (doesn't call getter)
// Explicitly return value if needed
vi.mock('./utils', () => ({
value: 42, // Not a getter
}));
// mockRestore no longer works on automocks
const spy = vi.spyOn(obj, 'method');
spy.mockRestore(); // Throws error if method is automocked
// Use unmock instead
vi.unmock('./module');
```
**Action Items**:
- [ ] Convert automocked getters to plain property values where needed
- [ ] Remove `.mockRestore()` calls on automocked methods
- [ ] Use `vi.unmock()` to clear automocks instead
- [ ] Test instance method isolation (they now share state with prototype)
#### 2.7 Settled Results Immediate Population
**Search Pattern**: `.mock.settledResults` in test files
**Changes Required**:
```typescript
// ✅ AFTER (Vitest 4.0)
const asyncMock = vi.fn(async () => 'result');
const promise = asyncMock();
// settledResults is immediately populated with 'incomplete' status
expect(asyncMock.mock.settledResults[0]).toEqual({
type: 'incomplete',
value: undefined,
});
// After promise resolves
await promise;
expect(asyncMock.mock.settledResults[0]).toEqual({
type: 'fulfilled',
value: 'result',
});
```
**Action Items**:
- [ ] Update tests that check `settledResults` before promise resolution
- [ ] Handle `'incomplete'` status in assertions
- [ ] Ensure tests properly await promises before checking settled results
### 3. Reporter and CLI Changes
#### 3.1 Reporter API Changes
**Search Pattern**: Custom reporters, `onCollected`, `onTaskUpdate`, `onFinished`
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default {
onCollected(files) {
// Handle collected files
},
onTaskUpdate(task) {
// Handle task update
},
onFinished(files) {
// Handle completion
},
};
// ✅ AFTER (Vitest 4.0)
// Use new reporter API - consult Vitest 4 docs for replacement methods
```
**Action Items**:
- [ ] Review custom reporters for removed API usage
- [ ] Consult Vitest 4 documentation for new reporter API
- [ ] Update or rewrite custom reporters to use new APIs
#### 3.2 Built-in Reporter Changes
**Search Pattern**: `reporters: ['basic']`, `reporters: ['verbose']`
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
export default defineConfig({
test: {
reporters: ['basic'],
},
});
// ✅ AFTER (Vitest 4.0)
export default defineConfig({
test: {
reporters: [['default', { summary: false }]], // Equivalent to 'basic'
},
});
// For verbose (tree output)
reporters: ['tree']; // Use 'tree' for hierarchical output
```
**Action Items**:
- [ ] Replace `'basic'` reporter with `['default', { summary: false }]`
- [ ] Replace `'verbose'` reporter with `'tree'` for hierarchical output
- [ ] Update CI configuration if reporters are specified there
### 4. Snapshot Changes
#### 4.1 Custom Elements Shadow Root
**Search Pattern**: Snapshot tests involving custom elements or Web Components
**Changes Required**:
```typescript
// ✅ AFTER (Vitest 4.0)
// Shadow root contents now printed by default in snapshots
// If you want old behavior (don't print shadow root):
export default defineConfig({
test: {
printShadowRoot: false,
},
});
```
**Action Items**:
- [ ] Review snapshot tests for custom elements
- [ ] Update snapshots if shadow root contents are now included
- [ ] Add `printShadowRoot: false` if old behavior is required
### 5. Environment Variable Updates
**Search Pattern**: CI/CD configuration files, `.env` files, documentation
**Changes Required**:
```bash
# ❌ BEFORE (Vitest 3.x)
VITEST_MAX_THREADS=4
VITEST_MAX_FORKS=2
VITE_NODE_DEPS_MODULE_DIRECTORIES=/custom/path
# ✅ AFTER (Vitest 4.0)
VITEST_MAX_WORKERS=4
VITEST_MODULE_DIRECTORIES=/custom/path
```
**Action Items**:
- [ ] Update CI/CD pipeline environment variables
- [ ] Update `.env` files
- [ ] Update documentation referencing old environment variables
- [ ] Search for `VITEST_MAX_THREADS`, `VITEST_MAX_FORKS`, `VITE_NODE_DEPS_MODULE_DIRECTORIES`
### 6. Advanced: Module Runner Changes
**Search Pattern**: `vitest/execute`, `__vitest_executor`, `vite-node`
**Changes Required**:
```typescript
// ❌ BEFORE (Vitest 3.x)
import { execute } from 'vitest/execute';
// Access to __vitest_executor
// ✅ AFTER (Vitest 4.0)
// Use Vite's Module Runner API instead
// Consult Vite Module Runner documentation
```
**Action Items**:
- [ ] If using `vitest/execute`, migrate to Vite Module Runner
- [ ] Remove dependencies on `__vitest_executor`
- [ ] Update custom pool implementations (complete rewrite needed)
### 7. Type Definition Updates
**Search Pattern**: TypeScript imports from `vitest`, type errors after upgrade
**Changes Required**:
```typescript
// All deprecated type exports removed
// If you get TypeScript errors about missing types:
// - Check if you're using deprecated type names
// - Update to current type names from Vitest 4 API
// - Remove explicit @types/node if it was only needed due to Vitest bug
```
**Action Items**:
- [ ] Run TypeScript compilation on all test files
- [ ] Fix any type errors related to removed Vitest type definitions
- [ ] Review `@types/node` usage (may no longer be accidentally included)
## Post-Migration Validation
### 1. Run Tests Per Project
```bash
# Test each project individually
nx run-many -t test -p PROJECT_NAME
```
### 2. Run All Tests
```bash
# Run tests across all affected projects
nx affected -t test
```
### 3. Check Coverage
```bash
# Verify coverage generation works with new config
nx affected -t test --coverage
```
### 4. Validate CI Pipeline
```bash
# Run full CI validation
nx prepush
```
### 5. Review Migration Checklist
- [ ] All configuration files updated
- [ ] All test files pass
- [ ] Coverage reports generate correctly
- [ ] CI/CD pipeline runs successfully
- [ ] Environment variables updated
- [ ] Documentation updated
- [ ] No deprecated API warnings in console
## Common Issues and Solutions
### Issue: Coverage includes too many files
**Solution**: Add explicit `coverage.include` patterns to match your source files
### Issue: Tests fail with "arrow function constructors not supported"
**Solution**: Convert arrow functions used as constructors to `function` keyword or `class` syntax
### Issue: Automocks not resetting between tests
**Solution**: Use `vi.unmock()` or `vi.resetModules()` instead of `vi.restoreAllMocks()`
### Issue: Mock call order assertions failing
**Solution**: Update to 1-based indexing for `invocationCallOrder`
### Issue: Browser tests failing after upgrade
**Solution**: Check browser provider is object format and imports use `vitest/browser`
### Issue: TypeScript errors in test files
**Solution**: Update to new type definitions and remove usage of deprecated types
## Files to Review
Create a checklist of all files that need review:
```bash
# Configuration files
find . -name "vitest.config.*" -o -name "vitest.workspace.*"
find . -name "project.json" -exec grep -l "vitest" {} \;
# Test files
find . -name "*.spec.*" -o -name "*.test.*"
# Files with mock usage
rg "vi\.(fn|spyOn|mock|restoreAllMocks)" --type ts --type tsx --type js
# Files with coverage config
rg "coverage\.(all|extensions|ignoreEmptyLines)" --type ts --type js
# CI configuration
find . -name ".github/workflows/*.yml" -o -name ".gitlab-ci.yml" -o -name "azure-pipelines.yml"
```
## Migration Strategy for Large Workspaces
1. **Migrate in phases**: Start with a small project, validate, then expand
2. **Use feature branches**: Create separate branches for different migration aspects
3. **Run tests frequently**: After each configuration change, run affected tests
4. **Document issues**: Keep track of project-specific issues and solutions
5. **Automate where possible**: Create codemods for repetitive changes
## Useful Commands During Migration
```bash
# Find all vitest configurations
nx show projects --with-target test
# Test specific project after changes
nx test PROJECT_NAME
# Test all affected
nx affected -t test
# View project details
nx show project PROJECT_NAME --web
# Clear Nx cache if needed
nx reset
```
## Guard Rails
DO NOT
- Force tests to pass by removing test logic and replacing it with `expect(true).toBe(true)`
- Remove assertions
- Add additional mocks that force tests to pass
---
## Notes for LLM Execution
When executing this migration:
1. **Work systematically**: Complete one category before moving to the next
2. **Test after each change**: Don't batch all changes without validation
3. **Keep user informed**: Report progress through each section
4. **Handle errors promptly**: If tests fail, fix immediately before proceeding
5. **Update documentation**: Note any workspace-specific patterns or issues
6. **Create meaningful commits**: Group related changes together with clear messages
7. **Use TodoWrite tool**: Track migration progress for visibility