Workflow migracji frameworków w Cursor
Twoja aplikacja React używa komponentów klasowych, Redux z connect(), React Router v5 i niestandardowego builda Webpack. Zespół chce przejść na komponenty funkcyjne z hookami, Zustand do zarządzania stanem, React Router v7 i Vite. Jest 180 komponentów, 45 kontenerów podłączonych do Redux i 30 definicji tras. Pełny rewrite zajmie miesiące i zatrzyma rozwój nowych funkcji. Stopniowa migracja pozwala dalej dostarczać funkcjonalności podczas modernizacji — ale potrzebujesz systematycznego podejścia, aby nie skończyć z bazą kodu, która na zawsze jest w połowie starych wzorców i w połowie nowych.
Migracje frameworków to jeden z najsilniejszych przypadków użycia Cursor. Transformacje są mechaniczne (konwersja składni klas na funkcje, zamiana jednego API na inne), wzorce są dobrze udokumentowane, a wolumen jest na tyle duży, że wsparcie AI zwraca się wielokrotnie. Wyzwanie nie polega na pojedynczej transformacji — polega na orkiestracji 180 takich transformacji bez psucia czegokolwiek.
Co wyniesiesz z tej lekcji
Dział zatytułowany „Co wyniesiesz z tej lekcji”- Workflow planowania, który mapuje zakres migracji przed zmianą jakiegokolwiek kodu
- Prompty do automatycznej transformacji plik po pliku z walidacją
- Strategia strangler fig, która pozwala migrować przyrostowo bez “wielkiego wybuchu”
- Techniki obsługi najtrudniejszych migracji (zarządzanie stanem, routing, narzędzia budowania)
- Reguły projektu, które zapobiegają mieszaniu starych i nowych wzorców w nowym kodzie
Planowanie migracji
Dział zatytułowany „Planowanie migracji”Każda migracja zaczyna się od inwentaryzacji. Musisz wiedzieć dokładnie, co migrujesz, ile plików jest dotkniętych i jakie transformacje są potrzebne. Tryb Plan jest do tego stworzony.
Tryb Plan przeskanuje twoją bazę kodu i wyprodukuje ustrukturyzowany podział. Typowy wynik może wyglądać tak:
- 95 prostych komponentów klasowych (bez stanu, bez lifecycle) — migracja automatyczna
- 50 średnich komponentów (stan i componentDidMount) — półautomatyczne
- 35 złożonych komponentów (wiele lifecycle methods, shouldComponentUpdate) — wymaga przeglądu
- 45 komponentów podłączonych do Redux — zależy od migracji Zustand
- 30 definicji tras — migracja wsadowa po komponentach
Ta inwentaryzacja staje się twoją mapą drogową migracji.
Wzorzec Strangler Fig
Dział zatytułowany „Wzorzec Strangler Fig”Najbezpieczniejsza strategia migracji to strangler fig: nowy kod używa nowych wzorców, stary kod jest migrowany przyrostowo, a oba współistnieją do ukończenia migracji. Reguły projektu Cursor egzekwują tę granicę.
# Reguły migracji (aktywne)
## Nowy kod- Wszystkie nowe komponenty MUSZĄ być komponentami funkcyjnymi z hookami- Całe nowe zarządzanie stanem MUSI używać store'ów Zustand- Wszystkie nowe trasy MUSZĄ używać wzorca data loader z React Router v7- Nowy kod nie może używać: komponentów klasowych, Redux connect(), React Router v5 Switch
## Współistnienie- Stare komponenty klasowe mogą importować nowe hooki przez funkcje wrapper- Stare komponenty podłączone do Redux mogą czytać ze store'ów Zustand przez bridge- Oba systemy routingu działają jednocześnie przez warstwę kompatybilności
## Status migracji- Komponenty: 45/180 zmigrowanych (25%)- Store'y Redux: 2/8 zmigrowanych (25%)- Trasy: 0/30 zmigrowanych (0%)Aktualizuj status migracji w tym pliku reguł w miarę postępów. Agent czyta go przy każdej interakcji, więc zawsze zna aktualny stan migracji.
Migracja komponentów
Dział zatytułowany „Migracja komponentów”Proste komponenty (bezstanowe)
Dział zatytułowany „Proste komponenty (bezstanowe)”Najłatwiejsza migracja: komponenty klasowe bez stanu i bez lifecycle methods.
Do migracji wsadowej możesz przetwarzać wiele plików naraz:
Zmigruj te 5 bezstanowych komponentów klasowych na komponenty funkcyjne.Zastosuj tę samą transformację do każdego:
@src/components/Badge.tsx@src/components/Card.tsx@src/components/Divider.tsx@src/components/Icon.tsx@src/components/Label.tsx
Dla każdego pliku: przekonwertuj klasę na funkcję, zdestrukturyzuj props, zachowaj zachowanie dokładnie.Po migracji uruchom "npm run type-check", aby zweryfikować kompilację TypeScript.Średnie komponenty (lifecycle methods)
Dział zatytułowany „Średnie komponenty (lifecycle methods)”Komponenty ze stanem i lifecycle methods wymagają ostrożniejszej transformacji:
@src/components/UserProfile.tsx
Zmigruj ten komponent klasowy na komponent funkcyjny:
1. componentDidMount -> useEffect z pustą tablicą zależności2. componentDidUpdate(prevProps) -> useEffect z zależnością od konkretnych props3. componentWillUnmount -> funkcja czyszcząca useEffect4. this.state + this.setState -> hooki useState (jeden per zmienną stanu)5. Metody instancji -> useCallback tam, gdzie używane jako event handlery6. getDerivedStateFromProps -> oblicz podczas renderowania lub useMemo
Zmapuj każdą lifecycle method na jej odpowiednik w hookach. Pokaż przed/podla każdej transformacji w komentarzach, aby recenzent zrozumiał mapowanie.
Zachowaj dokładnie takie samo zachowanie komponentu. Zwróć uwagę na:- Inicjalizacja stanu zależna od props- Logika czyszczenia (timery, subskrypcje, event listenery)- Warunkowe efekty oparte na zmianach propsZłożone komponenty (HOC-e, render props)
Dział zatytułowany „Złożone komponenty (HOC-e, render props)”Złożone komponenty wymagają indywidualnej uwagi:
@src/containers/OrderDashboard.tsx @src/store/ordersReducer.ts
Ten komponent używa:- connect() z react-redux z mapStateToProps i mapDispatchToProps- withRouter() HOC z react-router-dom- Render prop z komponentu <Query> do pobierania danych
Zmigruj go krok po kroku:1. Zamień connect() na hook store'u Zustand (utwórz store, jeśli potrzeba)2. Zamień withRouter() na hooki useNavigate() i useParams()3. Zamień render prop <Query> na hook useQuery z React Query4. Przekonwertuj klasę na komponent funkcyjny
Utwórz store Zustand w src/stores/orders.ts, który zastąpi reducer ReduxordersReducer. Powinien utrzymać ten sam kształt stanu i akcje.
Pokaż migrację jako serię commitów:- Commit 1: Utwórz store Zustand obok Redux- Commit 2: Przekonwertuj komponent na funkcyjny z hookami- Commit 3: Usuń stary reducer i pliki akcji ReduxMigracja zarządzania stanem
Dział zatytułowany „Migracja zarządzania stanem”Migracja Redux do Zustand jest najwyższego ryzyka, ponieważ zarządzanie stanem dotyka każdego podłączonego komponentu. Migruj jeden store naraz.
Migracja routingu
Dział zatytułowany „Migracja routingu”Migrację routera najlepiej przeprowadzić wsadowo, ponieważ trasy są od siebie zależne:
@src/routes @src/App.tsx
Zmigruj z React Router v5 do React Router v7:
1. Zamień <Switch> na <Routes>2. Zamień <Route component={X}> na <Route element={<X />}>3. Zamień <Redirect> na <Navigate>4. Zamień useHistory() na useNavigate()5. Zamień match.params na useParams()6. Zamień location.search na useSearchParams()7. Dodaj data loadery dla tras, które pobierają dane przy montowaniu
Kroki migracji:- Najpierw: Zaktualizuj definicje tras w App.tsx (zmiana wsadowa)- Potem: Zaktualizuj każdy komponent używający hooków routingu (po jednym)- Na koniec: Dodaj data loadery zastępujące wywołania API w componentDidMount
Zachowaj warstwę kompatybilności: jeśli trasa używa zarówno starych, jak i nowych wzorcówpodczas migracji, powinna nadal działać.Migracja narzędzia budowania
Dział zatytułowany „Migracja narzędzia budowania”Migracja Webpack do Vite jest zazwyczaj robiona w jednej sesji, ponieważ dotyczy tylko konfiguracji:
@webpack.config.js @babel.config.js @tsconfig.json @package.json
Zmigruj z Webpack 4 do Vite:
1. Utwórz vite.config.ts z: - Pluginem React - Wsparciem TypeScript - Aliasami ścieżek pasującymi do naszego webpack resolve.alias - Konfiguracją proxy pasującą do naszego devServer.proxy - Obsługą zmiennych środowiskowych (REACT_APP_ -> VITE_)
2. Zaktualizuj tsconfig.json: - Dodaj typy klienta Vite - Zaktualizuj rozwiązywanie modułów, jeśli potrzeba
3. Zaktualizuj użycie import.meta.env: - Znajdź wszystkie odwołania process.env.REACT_APP_ - Zamień na import.meta.env.VITE_ - Utwórz plik .env ze zmienionymi nazwami zmiennych
4. Zaktualizuj index.html: - Przenieś z public/ do katalogu głównego projektu - Dodaj tag skryptu modułu dla entry pointu
5. Zaktualizuj skrypty w package.json: - dev: vite - build: vite build - preview: vite preview
Wylistuj wszelkie pluginy webpack, które potrzebują odpowiedników w Vite.NIE usuwaj jeszcze konfiguracji webpack -- zachowaj ją jako fallback do zweryfikowania.Kiedy to się psuje
Dział zatytułowany „Kiedy to się psuje”Agent migruje kod niepoprawnie, a testy przechodzą, ponieważ testy też są nieaktualne. To najgroźniejszy błąd migracji. Przed migracją komponentu zweryfikuj, że jego istniejące testy faktycznie testują zachowania, na których ci zależy. Poproś Agenta: “Przed migracją tego komponentu przejrzyj jego plik testowy. Czy testy pokrywają kluczowe zachowania, czy tylko sprawdzają, że się renderuje?”
Bridge migracyjny powoduje problemy z wydajnością. Synchronizacja stanu między Redux a Zustand przy każdej zmianie tworzy niepotrzebne re-rendery. Utrzymuj bridge prostym (synchronizacja jednokierunkowa) i usuń go, gdy tylko wszystkie konsumenci danego store’u będą zmigrowane.
Częściowo zmigrowany kod myli Agenta. Gdy twoja baza kodu ma zarówno stare, jak i nowe wzorce, Agent czasem generuje kod używając starego wzorca, ponieważ widzi więcej jego przykładów. Plik reguł migracji na początku tego artykułu temu zapobiega — ale tylko jeśli jest ustawiony na “Always Apply.”
Migracja zatrzymuje się na 80%. Ostatnie 20% komponentów jest zawsze najtrudniejsze, ponieważ to najbardziej złożone komponenty. Nie zostawiaj ich. Zaplanuj dedykowane sprinty migracyjne i użyj trybu Plan w Cursor, aby rozbić każdy złożony komponent na mniejsze, łatwiejsze do ogarnięcia kroki.
Potrzebny jest rollback po częściowej migracji. Zachowaj stare ścieżki kodu dostępne (zakomentowane lub za feature flagami) do czasu zweryfikowania migracji na produkcji. Checkpointy Cursor pomagają z rollbackami per sesja, ale dla wielodniowych migracji używaj gałęzi Git.