Ratowanie wydajności dużej aplikacji przepisywanej na Vue 3
Kontekst
Zespół przepisywał dużą aplikację z Vue 2 na Vue 3. Nowa wersja korzystała z architektury feature-based, TanStack Query do pobierania danych oraz SignalR do aktualizacji w czasie rzeczywistym. Stack był nowoczesny, ale aplikacja już przed wdrożeniem wykazywała poważne problemy z wydajnością.
Problem
-
Niewydajny kod. W części aplikacji występowała zbędna
złożoność, zagnieżdżone pętle oraz wywołania
watchEffect, które przez swoje zależności uruchamiały się ponownie. - TanStack Query używany jako szyna zdarzeń. Stan aplikacji był powiązany przez queries i mutations uruchamiane z miejsc, które nie powinny musieć o sobie wiedzieć.
-
Kaskady requestów. Reaktywne zapytania uruchamiane wewnątrz
watchEffectpowodowały, że jedno wywołanie uruchamiało kolejne, tworząc łańcuch zależnych od siebie requestów zamiast jawnego przepływu danych. - Szum w code review. Formatowanie nie było konsekwentnie egzekwowane, więc pull requesty zawierały zmiany utrudniające skupienie się na logice i architekturze.
Co zrobiłem
- Przeniosłem formatowanie i lintowanie do narzędzi. Wprowadziłem Biome oraz git hooki, dzięki czemu formatowanie i podstawowe zasady spójności były sprawdzane automatycznie, zanim kod trafił do review.
- Rozdzieliłem odpowiedzialności. Uporządkowałem granice pomiędzy modułami i widokami oraz usunąłem niepotrzebne zależności pomiędzy store'ami.
- Scentralizowałem dostęp do danych. Klienci API, queries, mutations i query keys trafiły do jednej typowanej warstwy danych. Dzięki temu aplikacja ma jedno miejsce definiujące sposób pobierania i identyfikowania danych.
- Zbudowałem celowaną inwalidację. Wprowadziłem mechanizm sterowany zdarzeniami SignalR, dzięki któremu każda wiadomość unieważnia tylko te zapytania, których rzeczywiście dotyczy.
- Usunąłem łańcuchowe requesty. Wyeliminowałem kaskady tworzone przez reaktywne zapytania, a przy okazji wprowadziłem dziesiątki mniejszych poprawek dotyczących wydajności i architektury.
Efekt
- 0 pozostałych kaskad requestów w analizowanych przepływach
- 1 typowana warstwa danych dla klientów API, queries, mutations i query keys
- Celowana inwalidacja danych w czasie rzeczywistym sterowana zdarzeniami SignalR
- Automatyczne formatowanie i lintowanie przed code review
Efektem był znacznie bardziej przejrzysty przepływ danych, brak pozostałych kaskad requestów w analizowanych miejscach oraz środowisko developerskie, które automatycznie wychwytuje problemy z formatowaniem i podstawową spójnością kodu.
Dlaczego migracja miała tutaj znaczenie
Aplikacja była już przepisywana na Vue 3, ale nowszy framework nie sprawił automatycznie, że stała się lepsza. Rewrite przeniósł część starych nawyków architektonicznych do nowego kodu.
Rozwiązanie tych problemów w trakcie migracji pozwoliło zespołowi zakończyć przejście na Vue 3 z czytelniejszą warstwą danych, mniejszą liczbą ukrytych zależności i mniejszym ryzykiem ponownego wprowadzenia tych samych klas problemów z wydajnością.
Stack
Vue 3, TypeScript, TanStack Query, SignalR, Biome, architektura feature-based.
Tego rodzaju pracę oferuję w ramach audytu wydajności frontendu oraz migracji Vue 2 do Vue 3.