Skip to content
← Wszystkie wpisy
5 min czytania Dawid Skłodowski

Migracja jQuery do Stimulus, strona po stronie

Większość ustalonych aplikacji Rails niesie lata jQuery, a wielkowybuchowe przepisanie to pułapka. Deep-dive o przyrostowej migracji jQuery do Stimulus — strategia współistnienia, wzorce, które się tłumaczą, i jak to zrobić bez zatrzymywania pracy nad funkcjami.

Większość aplikacji Rails z jakąkolwiek historią niesie osad jQuery — lata $(document).ready, handlerów podpiętych selektorem, manipulacji DOM rozrzuconej po plikach. Działa, ale trudno to utrzymać, jest kruche pod Turbolinks/Turbo i coraz bardziej niezgodne z aplikacją opartą na Hotwire. Celem jest migracja do Stimulus, a krytyczną decyzją jest jak: wielkowybuchowe przepisanie to klasyczna pułapka — zatrzymuje pracę nad funkcjami, ryzykuje regresje wszędzie naraz i rzadko się kończy. Właściwym podejściem jest przyrostowe, strona po stronie. Oto jak to zrobić.

Dlaczego przyrostowo, nie wielkim wybuchem

Pokusą przy legacy kodzie jest odłożenie kilku tygodni i „po prostu przepisanie JavaScriptu”. Niemal nigdy nie działa: jQuery dotyka więcej, niż myślisz, regresje pojawiają się w miejscach, których nikt nie pamiętał, a praca nad funkcjami stoi, gdy się to wlecze. Migracja przyrostowa — konwertowanie jednego zachowania naraz, gdy reszta dalej działa — to wzorzec strangler zastosowany do frontowego JS, ten sam instynkt co migracja Mongo-do-Postgresa. jQuery i Stimulus współistnieją szczęśliwie podczas przejścia (to po prostu JavaScript na tej samej stronie), więc migrujesz w zrównoważonym tempie, wysyłając funkcje przez cały czas, a aplikacja zawsze działa. Bez zamrożenia, bez wielkiego ryzykownego przełączenia.

Konfiguracja współistnienia

Pierwszym krokiem jest sprawienie, by oba żyły obok siebie czysto. Dodajesz Stimulus (teraz standardowy z Hotwire) obok istniejącego jQuery, a od tej chwili reguła jest prosta: cały nowy JavaScript to Stimulus, a istniejące jQuery konwertujesz oportunistycznie. Sama ta reguła zatrzymuje rośnięcie problemu — jQuery jest teraz skończoną, kurczącą się stertą, a nie czymś, do czego ciągle dodajesz.

Praktyczna uwaga o Turbo: jeśli przechodzisz też na Turbo/Turbolinks, stary problem $(document).ready jQuery (handlery odpalające się raz i umierające przy nawigacji) staje się dotkliwy — co jest dodatkową motywacją, bo kontrolery Stimulus nie mają tego problemu (doczepiają się do markupu, ilekroć się pojawia). Często jQuery powodujące bóle głowy z Turbo to dokładnie jQuery do migracji najpierw.

Wzorce tłumaczenia

Większość konwersji jQuery-do-Stimulus podąża za garścią mechanicznych wzorców. Gdy je przyswoisz, praca jest stała, a nie zagadkowa:

  • $(document).on("click", ".foo", …) → akcja Stimulus. Delegacja zdarzeń selektorem staje się deklaratywnym data-action w markupie wskazującym metodę kontrolera:

    <!-- przedtem: handler podpięty gdzieś w pliku .js selektorem -->
    <!-- potem: -->
    <button data-controller="toggle" data-action="toggle#flip">…</button>
  • Zapytania DOM $(".something") → targety. Zamiast odpytywać DOM selektorem, nazwij element jako target i użyj this.somethingTarget — bez kruchych selektorów, zawężone do kontrolera.

  • Stan przechowywany w klasach / atrybutach data przez jQuery → klasy i values Stimulus. Gdzie jQuery przełączało klasy albo czytało atrybuty data- doraźnie, użyj API classes i values kontrolera, by konfiguracja żyła w markupie, typowana.

  • $(document).ready(initWidget) → connect() kontrolera. Inicjalizacja, która działała na ready, przenosi się do kontrolera, który uruchamia connect(), ilekroć jego element się pojawia — i poprawnie ponownie uruchamia po nawigacji Turbo, naprawiając błąd przy okazji.

Konwersja to w dużej mierze znalezienie jQuery dla jednego zachowania, zidentyfikowanie jego elementu i ponowne wyrażenie tego jako małego kontrolera z akcjami i targetami. To powtarzalne, ale proste, co jest dokładnie tym, co czyni to bezpiecznym do zrobienia przyrostowo.

Rób to strona po stronie (albo zachowanie po zachowaniu)

Praktyczną jednostką migracji jest strona albo samodzielne zachowanie. Wybierz jedno — powiedzmy modal na stronie produktu albo wszystkie przełączniki w ekranie ustawień — skonwertuj tylko to do Stimulus, przetestuj, wyślij i idź dalej. Wypada z tego kilka zalet:

  • Każda migracja jest mała i wysyłalna. Konwertujesz jeden widżet, weryfikujesz go i wdrażasz — niskie ryzyko, bez gigantycznego PR, bez długo żyjącej gałęzi.
  • Budujesz reużywalną bibliotekę kontrolerów po drodze. Za pierwszym razem, gdy konwertujesz dropdown, piszesz generyczny kontroler dropdown; następny dropdown go reużywa. Migracja produkuje małą bibliotekę generycznych kontrolerów z wpisu „Stimulus, który się skaluje”, więc późniejsze konwersje robią się szybsze.
  • Praca nad funkcjami nigdy nie ustaje. Ponieważ migrujesz oportunistycznie — często konwertując jQuery na stronie, którą już dotykasz dla funkcji — migracja jedzie obok normalnej pracy, zamiast z nią konkurować.

Użyteczna taktyka: migruj jQuery na stronie, gdy i tak musisz dotknąć tej strony dla funkcji albo błędu. Kod jest już w twojej głowie, testowanie już się dzieje, a migracja jest niemal darmowa. Z czasem strony o najwyższym ruchu i najczęściej zmieniane konwertują się naturalnie, a pozostałe jQuery jest na stabilnych stronach, których nikt nie dotyka — które w porządku zostawić na koniec (albo na zawsze).

Pułapki

Kilka rzeczy do wypatrzenia:

  • Globalne wtyczki jQuery i współdzielony stan. Część legacy jQuery polega na wtyczkach albo globalnym stanie, który kilka stron dzieli; rozplątanie tego wymaga więcej troski niż samodzielny widżet. Zmapuj zależności przed konwersją.
  • Nie konwertuj martwego kodu. Część jQuery obsługuje funkcje już nieużywane. Przed migracją zachowania sprawdź, że wciąż jest potrzebne — usunięcie bije konwersję.
  • Trzymaj kontrolery małe, gdy konwertujesz. Pokusą jest zrzucenie całego jQuery strony do jednego dużego kontrolera. Oprzyj się jej (zgodnie z dyscypliną Stimulus-który-się-skaluje) — konwertuj do kilku małych, jednoprzeznaczeniowych kontrolerów, inaczej właśnie przeniosłeś bałagan.
  • Testuj skonwertowane zachowanie. Migracja to świetny moment, by dodać test systemowy/feature, którego jQuery nigdy nie miało, by konwersja była zweryfikowana i pozostała działająca.

Werdykt

Migracja jQuery do Stimulus to realne i warte porządki, ale jak decyduje, czy się powiedzie: wielkowybuchowe przepisanie to pułapka, podczas gdy przyrostowa migracja strona-po-stronie — jQuery i Stimulus współistniejące, cały nowy JS jako Stimulus, istniejące jQuery konwertowane oportunistycznie — czyni ją bezpieczną, wysyłalną i zgodną z trwającą pracą nad funkcjami. Tłumaczenie jest mechaniczne (delegowane handlery → akcje, zapytania DOM → targety, ready → connect), jednostką jest strona albo zachowanie, a migracja wygodnie buduje twoją reużywalną bibliotekę kontrolerów po drodze. Konwertuj jQuery na stronach, które i tak dotykasz, trzymaj wynikowe kontrolery małe, usuwaj martwy kod zamiast go portować, a sterta legacy kurczy się stale bez zamrożenia. Lata jQuery stają się schludnym zbiorem kontrolerów Stimulus — nie w jednym heroicznym przepisaniu, lecz strona po stronie.