Strona główna / Artykuły / Wyspy, które można ponownie uruchomić na Bun: Lekcje projektowania z ramy dla ceramiki

Wyspy, które można ponownie uruchomić na Bun: Lekcje projektowania z ramy dla ceramiki

Jak framework z naciskiem na serwer traktuje HTML jako standard, ogranicza działanie JavaScript do oddzielnych obszarów, a także zajmuje się statycznym eksportem, błędami, CSP oraz wdrażaniem.

3252 słów

Większość stron w Internecie składa się z treści z kilkoma interaktywnymi elementami dodanymi na górze, jednak dominujący model rozwoju wysyła całą stronę do przeglądarki jako aplikację JavaScript. Stoneware, młody framework typu TypeScript o otwartym kodzie źródłowym stworzony na bazie Bun, wychodzi z przeciwnej założenia: HTML jest tym, co przeglądarka otrzymuje domyślnie, a komponent musi wyraźnie się na to zgodzić, zanim zostanie dla niego wysłany jakikolwiek JavaScript. Przegląd jego projektu to przydatny sposób na zrozumienie koncepcji „wysp”, możliwości ponownego uruchomienia, statycznego eksportu oraz mniej oczywistych aspektów inżynierii frameworków, takich jak komunikaty o błędach, zasady bezpieczeństwa i pakietowanie aplikacji przed wdrożeniem. Pod koniec powinieneś być w stanie ocenić, kiedy architektura oparta na serwerze i „wyspach” nadaje się do twojego projektu, oraz na jakie pułapki należy uważać podczas jej tworzenia lub wdrażania.

Dlaczego strona z treścią nie powinna stać się aplikacją

Załóżmy typową stronę produktu. Zawiera ona tytuł, zdjęcie, opis, listę specyfikacji, cenę, powiązane produkty, recenzje oraz elementy nawigacyjne. Spośród tego wszystkiego prawdopodobnie tylko dwie rzeczy faktycznie reagują na użytkownika: menu mobilne oraz przycisk „Dodaj do koszyka”. Wszystko inne to treść statyczna, której serwer już potrafi wygenerować.

Podejście oparte na renderowaniu przez klienta lub pełnym załadunku danych nadal wymaga od przeglądarki pobrania, zinterpretowania i wykonania kodu reprezentującego całą stronę, aby te dwa elementy mogły funkcjonować. Pytanie z perspektywy serwera jest proste: a co, jeśli przeglądarka otrzymałaby kod tylko dla tych części, które go potrzebują?

Model mentalny: HTML plus wyspy

Architektura dzieli stronę na dwa rodzaje obszarów. Większa część to HTML generowany na serwerze. Elementy interaktywne stają się „wyspami” – małymi, samodzielnymi regionami, które zawierają własny kod JavaScript. Oba rodzaje elementów znajdują się w tym samym dokumencie w przeglądarce.

Web page
                            │
                ┌───────────┴───────────┐
                │                       │
             HTML                    Islands
                │                       │
        Server rendered          JavaScript
                │                       │
                └───────────┬───────────┘
                            │
                         Browser

Głównym skutkiem jest to, że interaktywność nie zmusza już do wysyłania całego aplikacji. Uczynienie jakiegoś widgetu interaktywnym oznacza konieczność przesłania tylko kodu tego widgetu, a nie całej strony.

Budowanie na Bun zamiast kompletowania zestawu narzędzi

Wybór Bun nie oznacza, że Node.js jest przestarzały. Node posiada ogromny ekosystem i służy do obsługi dużej części aplikacji JavaScript w produkcji; nadal jest doskonałym środowiskiem wykonawczym. Interesujące jest to, co zmienia się, gdy framework jest projektowany wokół środowiska wykonawczego, które już zawiera narzędzia niezbędne w większości projektów.

Bun dostarcza środowisko wykonawcze JavaScript wraz z menedżerem pakietów, narzędziem do łączenia plików oraz narzędziem do testowania. Dla twórców frameworków oznacza to eliminację wielu dodatkowych elementów. Zamiast budować warstwy – najpierw framework na Node, potem menedżer pakietów, następnie oddzielne narzędzie do łączenia plików i osobne narzędzie do testowania – projekt może traktować je wszystkie jako jedną spójną bazę.

Bun
                     │
        ┌────────────┼────────────┐
        │            │            │
      Runtime     Tooling       Testing
        │            │            │
        └────────────┼────────────┘
                     ↓
                 Stoneware

Warto jasno rozróżniać role: Bun to platforma, a Stoneware to framework działający na niej. Jeśli chcesz szerszego porównania samych środowisk wykonawczych, zapoznaj się z porównaniem Node.js, Deno i Bun.

HTML na pierwszym miejscu, traktowane poważnie

Renderowanie po stronie serwera istnieje od dawna, więc zwrot „renderowanie HTML na serwerze” nie wydaje się niczym wyjątkowym. Silniejszą zasadą Stoneware jest to, że serwer powinien wygenerować naprawdę przydatny HTML, zanim przeglądarka będzie musiała cokolwiek rozumieć na temat aplikacji.

Weźmy komponent, który wyświetla produkt wraz z tytułem i ceną.

<ProductCard
  title="MacBook Pro"
  price={1999}
/>

W tym komponencie nie ma nic, co wymagałoby od przeglądarki przechowywania jego modelu w JavaScript. Serwer może zamienić go na zwykły kod markup:

<div class="product-card">
  <h2>MacBook Pro</h2>
  <span>$1999</span>
</div>

To wyjście jest już kompletnie gotowe. Ludzie mogą je czytać, roboty wyszukiwarek mogą je indeksować, a przeglądarka może je natychmiast wyświetlić. W dostarczaniu samego treści nie bierze udziału żaden skrypt.

Cięte decyzje dotyczące JavaScript

Teraz dodajmy przycisk koszyka. W odróżnieniu od karty produktu musi reagować na kliknięcia, aktualizować stan i prawdopodobnie komunikować się z API.

<AddToCart product={product} />

To komponent jest miejscem, w którym uzasadniane jest zachowanie po stronie klienta, dlatego staje się „wyspą”. Reszta strony pozostaje w formie HTML, a ostateczna strona wygląda tak:

Product page
│
├── Product title          HTML
├── Product description    HTML
├── Product image          HTML
├── Product specifications HTML
│
└── Add to cart            JavaScript island

Strona nie jest „bez JavaScripta”. Jest skryptowana selektywnie, a wybór dokonywany jest dla poszczególnych komponentów, a nie całej strony. Ta różnica ma znaczenie, ponieważ pozwala zachować prostotę domyślnych rozwiązań i sprawia, że każdy fragment kodu staje się widocznym, świadomym wyborem.

Gdzie znajduje się granica „wyspy”

Wyspa oznacza granicę pomiędzy treścią renderowaną na serwerze a funkcjonalnościami działającymi po stronie klienta. Strona dokumentacyjna wyraźnie pokazuje ten wzorzec. Treść artykułu, nagłówki, przykłady kodu, obrazy, linki, elementy nawigacyjne oraz stopka to wszystko treść. Tylko kilka funkcji jest naprawdę interaktywnych: wyszukiwarka, przełącznik tematów, przyciski kopiowania do schowka kodu oraz ewentualnie drzewo nawigacyjne, które można rozwijać.

Documentation page
│
├── Article ─────────────── SSR
├── Code blocks ─────────── SSR
├── Images ──────────────── SSR
├── Navigation ──────────── SSR
│
├── Search ──────────────── Island
├── Theme switcher ──────── Island
└── Copy button ─────────── Island

Taki rodzaj strony, składający się głównie z treści z kilkoma interaktywnymi obszarami, jest dokładnie tym, do czego zostało zaprojektowane to framework.

Hydryacja versus możliwość kontynuacji

Sprawiedliwą zastrzeżeniem jest stwierdzenie, że to wszystko to po prostu SSR. Częściowo tak jest – serwer renderuje HTML. Różnica polega na tym, co dzieje się po dotarciu tego HTML.

W przypadku klasycznej hydryacji sekwencja wygląda mniej więcej tak:

  • serwer wysyła HTML;
  • przeglądarka pobiera JavaScript aplikacji;
  • framework wykonywa i odbudowuje drzewo komponentów w pamięci;
  • obsługi zdarzeń są przypisywane do istniejącego DOM-u.
  • Przeglądarka ostatecznie odbudowuje aplikację, której wynik już otrzymała. Z punktu widzenia użytkownika jest to czysty nadmiar pracy – piksele były już na ekranie.

    Zamiast tego ceramika jest projektowana wokół możliwości wznowienia pracy poszczególnych obszarów. Serwer wysyła HTML wraz z danymi stanu potrzebnymi do działania tych interaktywnych obszarów, a przeglądarka kontynuuje pracę tam, gdzie serwer przerwał, zamiast ponownie wykonywać stronę, aby odzyskać ten stan. Celem jest zapobieganie temu, by małe interaktywne obszary zmuszały do pełnej odbudowy strony.

    Inny cel optymalizacji

    Koncepcja wznowialności zmienia sposób patrzenia na kwestię wydajności. Zamiast zastanawiać się, jak przyspieszyć proces hydratacji wszystkiego, pytamy o to, ile pracy przeglądarki można całkowicie uniknąć. Struktura danych zmienia się z „HTML wraz ze wszystkim JavaScriptem aplikacji plus jedna faza hydratacji” na „HTML wraz tylko z kodem niezbędnym do interakcji, przywracanie stanu zrenderowanego na serwerze”. Dla stron o dużej ilości treści jest to często znacznie większy atut niż jakakolwiek optymalizacja hydratacji.

    Jeśli pracujesz z React, ten sam cel leży u podstaw komponentów serwerowych; architektura stojąca za renderowaniem bez pliku bundle opisuje ten podejście i przedstawia przydatne porównanie.

    Podejście „serwer na pierwszym miejscu” to nie tylko serwer

    Żadne z tych argumentów nie przemawia przeciwko aplikacjom po stronie klienta. Edytory współpracy, narzędzia do projektowania, gry w przeglądarce oraz zaawansowane interaktywne aplikacje do obsługi danych mają zupełnie inne wymagania, a większość ich komponentów jest z natury interaktywna. Architektura ta skupia się na drugim końcu spektrum: stronach, gdzie większość treści jest naturalnie renderowana na serwerze, a interakcja stanowi wyjątek.

    Eksport statyczny wynika z tej samej koncepcji

    Jeśli HTML jest standardem, naturalnym następnym pytaniem jest to, dlaczego w ogóle należy uruchamiać serwer dla stron, które nigdy się nie zmieniają przy każdym żądaniu. Stoneware może eksportować aplikację jako pliki statyczne i przekazać je CDN.

    Stoneware application
            │
            ▼
         export
            │
            ▼
          dist/
            │
            ▼
           CDN
    

    Dokumentację, strony marketingowe oraz katalogi produktów można często przygotować z wyprzedzeniem i serwować bezpośrednio z edge. Trasy, które rzeczywiście wymagają logiki na poziomie każdej prośby, mogą pozostać renderowane na serwerze. Zaletą jest to, że przeniesienie trasy pomiędzy wersją statyczną a SSR nie wymaga zmiany modelu programowania całego aplikacji.

    Trasy dynamiczne wymagają wyraźnej listy ścieżek

    Eksport statyczny staje się trudniejszy, gdy tylko trasa zawiera parametr. Trasa taka jak /products/[sku] może, w zasadzie, odpowiadać nieograniczonej liczbie adresów URL, więc narzędzie eksportujące nie może odgadnąć, jakie strony należy utworzyć. Dlatego framework prosi trasę o ich wyliczenie:

    export function staticPaths() {
      return products.map(product => ({
        sku: product.sku
      }));
    }
    

    Z pomocą tej listy eksporter tworzy rzeczywisty plik HTML dla każdego znanej SKU, na przykład dist/products/laptop-1/index.html. W tym momencie projekt frameworka wykracza poza prostą renderzację JSX: framework musi zrozumieć, jak trasy, dane, krok budowania oraz cel deplojacji są ze sobą powiązane. Praktycznym przypadkiem krawędziowym, który należy uwzględnić, jest sytuacja, gdy dynamiczna trasa w ogóle nie ma metody staticPaths(); framework musi albo wyraźnie poinformować o błędzie podczas eksportu, albo utrzymać tę trasę w formie renderowanej na serwerze – milczące jej pominięcie jest najgorszą opcją.

    Wiadomości o błędach są częścią narzędzia renderującego

    W istocie renderer bierze komponent i tworzy HTML. Trudność polega na ogromnej różnorodności elementów dziecięcych i atrybutów, z którymi musi sobie poradzić: wartości tekstowe i liczbowe, tablice oraz null, elementy i zagnieżdżone komponenty, sygnały i atrybuty, błędy, prace asynchroniczne oraz, co nieuniknione, wartości, które nie mogą zostać wyrenderowane.

    Częstym błędem jest napisanie <span>{product}</span>, gdy chciano napisać <span>{product.name}</span>. Ogólne komunikaty typu „nie można wyrenderować wartości typu obiekt” prawie nic nie mówią o tym, gdzie szukać przyczyny. Stoneware natomiast opisuje konkretną wartość, która powoduje problem:

    Cannot render a plain object with keys: id, title, price.
    

    a następnie podaje ścieżkę komponentu, która do niej prowadzi:

    in <span>
    in <Price>
    in <ProductCard>
    in <Home>
    

    Wylistowanie kluczy obiektu wskazuje na właściwość, którą prawdopodobnie mieliśmy na myśli, a ślad komponentu wskazuje dokładny plik do otwarcia. Framework ocenia się nie tylko pod kątem prawidłowego przebiegu, ale także tego, jak szybko pomaga wyjść z sytuacji problematycznych.

    Gdy mikrotest ukrywa rzeczywisty koszt

    Początkowo zbieranie takiego śladu komponentu oznaczało otaczanie wielu operacji renderowania blokami try/catch. Izolowany mikrotest wskazywał, że dodatkowy koszt jest zaniedbywalny. Jednak przy rzeczywistym renderowaniu strony otaczanie każdego elementu sprawiało, że proces renderowania był o około 38% droższy.

    To wyjaśnienie jest znane każdemu, kto przeprowadza testy JavaScript: w małym, powtarzalnym teście kompilator optymalizujący silnika może usunąć lub przenieść dużą część pracy, którą próbujemy zmierzyć, więc uzyskana liczba odzwierciedla wersję kodu po optymalizacji.

    Mikropomiary mogą wprowadzać w błąd, gdy czas wykonywania optymalizuje dokładnie to, co jest mierzone.

    Rozwiązanie było strukturalne. Nakład pracy związaný z śledzeniem błędów został ograniczony do granic poszczególnych komponentów, a pojedyncze elementy wykorzystywały tańsze operacje zapisu i przywracania, aby utrzymać aktualny stan. Pomiarы typu A/B na rzeczywistych renderach nie wykazały żadnych istotnych różnic. Szersza lekcja polega na tym, że wydajność renderera zależy nie tylko od szybkości, ale także od unikania regresów podczas dodawania funkcji przyjaznych programistom, a wszelkie twierdzenia dotyczące wydajności powinny być weryfikowane na reprezentatywnych obciążeniach.

    Domyślne ustawienia bezpieczeństwa i kolejność przetwarzania

    Zwykła aplikacja nie powinna wymagać od programisty pamiętania o każdej z podstawowych funkcji bezpieczeństwa przed uruchomieniem w produkcji. Stoneware dostarczany jest z domyślnymi ustawieniami, takimi jak ochrona przed CSRF i obsługa Content Security Policy.

    Kolejność procesowania żądań jest celowa:

    • Najpierw uruchamiana jest ochrona CSRF;
    • Następnie działa middleware aplikacji;
    • Potem następuje dopasowywanie ścieżek i renderowanie;
    • Wszystko opuszcza aplikację przez jeden punkt odpowiedzi.

    Gdyby middleware aplikacji działał przed sprawdzeniem CSRF, kod użytkownika mógłby trafić na ścieżkę, która omija zasady bezpieczeństwa na poziomie frameworka – na przykład poprzez wczesne zakończenie obsługi żądania lub jego przepisanie. Zapisanie tej kolejności w samym frameworku, zamiast jedynie jej udokumentowania i oczekiwania, że wszyscy się do niej będą trzymać, to właśnie taka zasada, którą framework powinien określić. Jeden punkt wyjścia oznacza również, że nagłówki takie jak CSP są stosowane spójnie we wszystkich odpowiedziach.

    Rozszerzanie ścisłych zasad CSP bez ich wyłączania

    Zastrzeżona polityka jest dobrym standardem, ale prawdziwe strony ładują narzędzia analityczne, elementy płatności, API, czcionki webowe oraz mapy. Częstym problemem jest to, że programista napotka zablokowany skrypt i całkowicie wyłączy CSP. Lepszy projekt umożliwia rozszerzanie poszczególnych dyrektyw przy jednoczesnym zachowaniu reszty standardowej polityki:

    csp: {
      scriptSrc: ["https://www.googletagmanager.com"],
      connectSrc: ["https://www.google-analytics.com"],
      imgSrc: ["https://www.google-analytics.com"],
    }
    

    Zasada polega na bezpiecznych standardach wraz z wyraźną listą dopuszczalnych elementów dla stron trzecich, określoną dla każdej dyrektywy. Projektując takie API, należy jasno określić, czy dostarczony źródło uzupełnia standardową dyrektywę, czy ją zastępuje, oraz udokumentować tę decyzję – oba podejścia są możliwe, a różnica ma konsekwencje bezpieczeństwa.

    Najtrudniejsze błędy pojawiają się po procesorze renderowania

    Framework nie kończy się przy rendererze. Kod musi przetrwać całą drogę: od źródła, przez kompilator i renderer, aż po proces budowania, pliki assets, wdrożenie, CDN i wreszcie przeglądarkę. Niektóre z najtrudniejszych problemów pojawiają się pod koniec tej łańcuchowej ścieżki, daleko od kodu, który większość ludzi uważa za „framework”.

    Pakowanie plików island do Vercel

    Wersja 0.1.8 zmieniła sposób, w jaki Stoneware wdraża aplikacje na Vercel. Dla tego celu generowane fragmenty kodu klienta są teraz włączane do pliku serwera jako dane w formacie base64, dzięki czemu stają się częścią pliku, który platforma wdraża, i są dostarczane z adresu /_stoneware/*.

    Stoneware build
          ↓
    server bundle
          ├── server code
          ├── CSS assets
          └── island assets
                  ↓
              Vercel
                  ↓
          /_stoneware/*
    

    To zachowanie jest opcjonalne i dotyczy wyłącznie celu Vercel. Rozwiązanie typu container deployment ma już pliki na dysku, więc nie ma powodu, by przechowywać drugą kopię każdego fragmentu w pliku serwera. Ogólnie rzecz biorąc, platformy hostingowe różnią się tym, co włączają do procesu rozgłoszenia, dlatego obsługa zasobów często wymaga strategii dostosowanych do konkretnego celu, a nie jednej uniwersalnej odpowiedzi.

    Testy potwierdzające poprawkę

    Projekt zawiera ponad 500 automatycznych testów obejmujących renderer, router, mechanizmy islands i signals, arkusze stylów oraz serwowanie zasobów, eksport statyczny, mechanizmy CSRF i CSP, cele rozgłoszenia, raportowanie błędów oraz nieprawidłowe lub wrogie dane wejściowe, takie jak próby przechodzenia przez ścieżki, pliki binarne i błędnie sformatowane ścieżki do zasobów.

    Sama liczba testów nie jest kluczowa. Bardziej przydatnym kryterium jest to:

    Test regresji powinien pokazać, że zawiódłby on przed wprowadzeniem poprawki.

    Test, który przechodzi zarówno przed, jak i po zmianie, dokumentuje zachowanie, ale nie chroni przed powrotem błędu. Sprawdzanie, czy nowy test zawodzi w przypadku starego kodu, to tania praktyka, która sprawia, że zestaw testów staje się znacznie bardziej wiarygodny.

    Wykorzystywanie agenta kodującego bez zlecania projektowania

    Znaczna część Stoneware została zaimplementowana przy użyciu Claude’a jako agenta kodującego. Był on szczególnie skuteczny w badaniu rozwijającej się bazy kodu, pisaniu powtarzalnej infrastruktury, tworzeniu testów, analizowaniu błędów, refaktoryzacji, dokumentowaniu architektury oraz badaniu przypadków krawędziowych.

    Tego, czego nie mógł zrobić samodzielnie, było podjęcie decyzji o tym, jaka powinna być architektura. Trudne pytania dotyczyły aspektów architektonicznych:

    • Dla każdej trasy – czy SSR, czy eksport statyczny to właściwy tryb?
  • Jak powinien zachowywać się eksport dla dynamicznej trasy, która nie ma metody staticPaths()?
  • Jak powinien zareagować renderer, gdy komponent zwraca zwykły obiekt?
  • Które miejsca jest przeszukiwane podczas budowania, aby znaleźć pliki stylów?
  • Jak generowane fragmenty kodu dla klienta docierają do przeglądarki na Vercel?
  • Czy źródło CSP dostarczone przez programistę dodaje się do domyślnej dyrektywy czy ją przejmuje?
  • Agent może zbadać te pytania i zaimplementować wybraną odpowiedź, ale ktoś nadal musi zakwestionować taki projekt i sprawdzić wynik.

    Prawdopodobne nie jest to samo co poprawne

    Agent kodujący może bardzo szybko stworzyć przekonującą implementację, a ta szybkość jest cenna. Oznacza to jednak również, że może błędnie działać szybko. Problem z zasobami w Vercel ilustruje ten błąd pętli: pierwsza poprawka skopiowała utworzone zasoby do katalogu public/, co wydawało się sensowne i przeszło lokalne testy; jednak rzeczywista implementacja pokazała, że to założenie było błędne. Druga próba polegała na zmianie samego modelu implementacji. Testy przypadków krawędziowych ujawniły następnie kolejny błąd w tej wersji.

    Ten cykl to typowa praca inżyniera oprogramowania, a nie awaria sztucznej inteligencji. To, co się zmienia, to szybkość każdej iteracji, co sprawia, że weryfikacja od początku do końca w rzeczywistym środowisku docelowym staje się ważniejsza, a nie mniej istotna.

    Dlaczego wybór środowiska wykonawczego ma znaczenie poza szybkością

    Zredukowanie historii do stwierdzenia „Bun jest szybszy od Node” pomija sedno sprawy, a surowa szybkość i tak nie stanowi filozofii frameworka. Bardziej interesującym eksperymentem jest zaprojektowanie frameworka przy założeniu, że od samego początku dostępne są nowoczesny środowisko wykonywania oraz zintegrowany zestaw narzędzi. Połączenie w Bunie środowiska wykonywania, zarządzania pakietami, pakowania i testowania czyni go wygodną podstawą do tego rodzaju eksploracji architektonicznych.

    Gdzie pasuje ta architektura

    Taki podejście sprawdza się wtedy, gdy większość strony to treść, a tylko jej część jest interaktywna:

    • Dokumentacja: artykuły i przykłady kodu są renderowane na serwerze; funkcje takie jak wyszukiwanie, zmiana tematu i przyciski kopiowania stanowią oddzielne elementy.
    • E-commerce: szczegóły produktów, zdjęcia i treści SEO są renderowane na serwerze; koszyk zakupów i filtry to oddzielne elementy.
  • Strony firmowe: informacje o firmie, usługi i rynki są renderowane na serwerze; formularz kontaktowy stanowi oddzielną część lub wymaga interakcji z serwerem.
  • Strony z treścią: artykuły są renderowane na serwerze; komentarze i funkcja wyszukiwania to oddzielne elementy.
  • Gdzie prawdopodobnie nie nadaje się to narzędzie

    Jeśli twoje rozwiązanie to w rzeczywistości aplikacja desktopowa działająca w przeglądarce, taka jak edytor współpracy, narzędzie graficzne, gra, interaktywny panel sterowania lub każda aplikacja, w której prawie wszystkie komponenty działają na stronie klienta, udział strony, który może pozostać w formacie HTML, jest niewielki. W takim przypadku model „wysp” dodaje ograniczenia bez większej korzyści, a architektura skupiona na stronie klienta jest prawdopodobnie lepszym rozwiązaniem. Framework może mieć wyraźną opinię, nie udając, że nadaje się do każdego rodzaju zadań.

    Próba wykorzystania

    W chwili pisania ceramika jest nadal w wersji 0.1.x, więc należy się spodziewać niedoskonałości i sprawdzić stan w repozytorium. Planowane ulepszenia obejmują więcej integracji, lepszą diagnostykę i ostrzeżenia dotyczące rozwoju, więcej przykładów oraz celów implementacji, lepszą dokumentację i większą liczbę zastosowań w praktyce. Aby stworzyć szkielet projektu i uruchomić serwer deweloperski:

    bun create stoneware my-app
    cd my-app
    bun dev
    

    Dobrym pierwszym eksperymentem jest coś małego, ale bogatego w treść: blog, strona dokumentacyjna, katalog produktów, portfolio lub strona firmowa. Podczas tworzenia zadawaj sobie pytanie, ile z treści strony faktycznie wymaga JavaScriptu.

    Główne wnioski

    • Traktuj HTML jako standardowy format wyjściowy, a JavaScript na stronie klienta jako opcję do włączenia dla poszczególnych komponentów; dzięki temu strona będzie miała wybrane elementy z skryptami, a nie będzie pełną aplikacją.
  • Zmiana na model możliwości ponownego uruchomienia zmienia cel z szybszego ładowania na całkowite unikanie obciążenia przeglądarki, co przynosi największe korzyści na stronach o dużej ilości treści.
  • Eksport statyczny i SSR mogą współistnieć w jednym modelu programowania, ale ścieżki dynamiczne wymagają wyraźnego listy ścieżek.
  • Inwestuj w komunikaty o błędach, które wskazują na nieprawidłową wartość oraz ścieżkę komponentu; waliduj wydajność na rzeczywistych renderach, a nie tylko na mikrotestach.
  • Zawrzyj w frameworku kwestie związane z bezpieczeństwem, takie jak CSRF przed middleware, i umożliwiaj programistom rozszerzanie dyrektyw CSP zamiast wyłączania tej polityki.
  • Cele implementacji się różnią; sprawdź obsługę zasobów od początku do końca oraz pisz testy regresji, które zawiodą bez naprawy.
  • Agenty AI przyspieszają implementację, ale decyzje architektoniczne oraz weryfikacja w rzeczywistym środowisku pozostają obowiązkami ludzkimi.
  • Literatura pokrewna

  • Lekcje z przeniesienia w Bunie przy użyciu SI z Zig na Rust: Weryfikacja to prawdziwa praca — Co pokazuje przeprowadzone przez Bun przeniesienie z Zig na Rust przy pomocy agenta dotyczące zestawów testowych jako umów, przewodników portowania, kodu niebezpiecznego oraz dlaczego weryfikacja obecnie ogranicza programowanie przy użyciu SI.