# Framework Upgrade Paths Detailed upgrade procedures for major framework version transitions. --- ## React 18 to 19 ### Pre-Upgrade Checklist ``` [ ] Running React 18.3.x (last 18.x with deprecation warnings) [ ] All deprecation warnings resolved [ ] No usage of legacy string refs [ ] No usage of legacy context (contextTypes) [ ] No usage of defaultProps on function components [ ] No usage of propTypes at runtime [ ] Test suite passing on 18.3.x [ ] TypeScript 5.x or later (for type changes) ``` ### Step-by-Step Process 1. **Upgrade to React 18.3.x first** -- this version surfaces deprecation warnings for all APIs removed in 19. 2. **Fix all deprecation warnings** before proceeding. 3. **Run the official codemod:** ```bash npx codemod@latest react/19/migration-recipe --target src/ ``` 4. **Update package.json:** ```bash npm install react@19 react-dom@19 npm install -D @types/react@19 @types/react-dom@19 ``` 5. **Update react-dom entry point:** ```tsx // Before (React 18) import { createRoot } from 'react-dom/client'; // After (React 19) -- same API, but check for removed APIs below ``` 6. **Run tests and fix remaining issues.** ### Breaking Changes | Removed API | Replacement | |------------|-------------| | `forwardRef` | Pass `ref` as a regular prop | | `` | Use `` directly as provider | | `defaultProps` on function components | Use JS default parameters | | `propTypes` runtime checking | Use TypeScript or Flow | | `react-test-renderer` | Use `@testing-library/react` | | `ReactDOM.render` | Use `createRoot` (already required in 18) | | `ReactDOM.hydrate` | Use `hydrateRoot` (already required in 18) | | `unmountComponentAtNode` | Use `root.unmount()` | | `ReactDOM.findDOMNode` | Use refs | ### New APIs to Adopt ```tsx // use() hook -- read promises and context in render import { use } from 'react'; function UserProfile({ userPromise }: { userPromise: Promise }) { const user = use(userPromise); return

{user.name}

; } // useActionState -- form action with state import { useActionState } from 'react'; function LoginForm() { const [state, formAction, isPending] = useActionState( async (prev: State, formData: FormData) => { const result = await login(formData); return result; }, { error: null } ); return
...
; } // useOptimistic -- optimistic updates import { useOptimistic } from 'react'; function TodoList({ todos }: { todos: Todo[] }) { const [optimisticTodos, addOptimistic] = useOptimistic( todos, (state, newTodo: Todo) => [...state, newTodo] ); // ... } // ref as prop -- no more forwardRef function Input({ ref, ...props }: { ref?: React.Ref }) { return ; } // Context as provider const ThemeContext = createContext('light'); // Before: // After: ``` ### Verification Steps ```bash # Run type checking npx tsc --noEmit # Run tests npm test # Search for removed APIs that codemods may have missed rg "forwardRef" src/ rg "Context\.Provider" src/ rg "defaultProps" src/ --glob "*.tsx" rg "propTypes" src/ --glob "*.tsx" rg "findDOMNode" src/ rg "react-test-renderer" package.json ``` --- ## Next.js Pages Router to App Router ### Pre-Upgrade Checklist ``` [ ] Running latest Next.js 14.x or 15.x [ ] Understood Server vs Client Component model [ ] Identified pages that need client-side interactivity [ ] Reviewed data fetching strategy (no more getServerSideProps/getStaticProps) [ ] Identified API routes that need migration [ ] Middleware already using edge runtime (if applicable) ``` ### Step-by-Step Process 1. **Create `app/` directory** alongside existing `pages/`. 2. **Create `app/layout.tsx`** (replaces `_app.tsx` and `_document.tsx`): ```tsx export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` 3. **Migrate pages one at a time** -- both routers work simultaneously. 4. **Convert data fetching:** ```tsx // Before (Pages Router) export async function getServerSideProps() { const data = await fetchData(); return { props: { data } }; } export default function Page({ data }) { ... } // After (App Router) export default async function Page() { const data = await fetchData(); // direct async component return
{data}
; } ``` 5. **Convert dynamic routes:** ``` pages/posts/[id].tsx → app/posts/[id]/page.tsx pages/[...slug].tsx → app/[...slug]/page.tsx ``` 6. **Run the official codemod:** ```bash npx @next/codemod@latest ``` ### File Convention Changes | Pages Router | App Router | Purpose | |-------------|-----------|---------| | `pages/index.tsx` | `app/page.tsx` | Home page | | `pages/about.tsx` | `app/about/page.tsx` | Static page | | `pages/posts/[id].tsx` | `app/posts/[id]/page.tsx` | Dynamic page | | `pages/_app.tsx` | `app/layout.tsx` | Root layout | | `pages/_document.tsx` | `app/layout.tsx` | HTML document | | `pages/_error.tsx` | `app/error.tsx` | Error boundary | | `pages/404.tsx` | `app/not-found.tsx` | Not found page | | `pages/api/hello.ts` | `app/api/hello/route.ts` | API route | | N/A | `app/loading.tsx` | Loading UI (new) | | N/A | `app/template.tsx` | Re-mounted layout (new) | ### Data Fetching Migration | Pages Router | App Router | |-------------|-----------| | `getServerSideProps` | `async` Server Component (fetches on every request) | | `getStaticProps` | `async` Server Component + `fetch` with `cache: 'force-cache'` | | `getStaticPaths` | `generateStaticParams()` | | `getInitialProps` | Remove entirely -- use Server Components | | `useRouter().query` | `useSearchParams()` (client) or `searchParams` prop (server) | ### Common Breaking Changes - `useRouter` from `next/navigation` not `next/router` - `pathname` no longer includes query parameters - `Link` no longer requires `` child - CSS Modules class names may differ - `Image` component default behavior changes - Metadata API replaces `` component - Route handlers replace API routes (different request/response model) ### Verification Steps ```bash # Check for Pages Router imports in migrated files rg "from 'next/router'" app/ rg "getServerSideProps|getStaticProps|getInitialProps" app/ rg "next/head" app/ # Verify all routes work npm run build # catches most issues at build time npm run dev # test interactive behavior ``` --- ## Vue 2 to 3 ### Pre-Upgrade Checklist ``` [ ] Identified all breaking syntax changes (v-model, filters, events) [ ] Listed third-party Vue 2 plugins that need Vue 3 equivalents [ ] Decided on migration approach: migration build (@vue/compat) vs direct [ ] Decided on state management: Vuex → Pinia migration [ ] Test suite passing on Vue 2 ``` ### Step-by-Step Process (Using Migration Build) 1. **Upgrade to Vue 2.7** first (backports Composition API, `