Front-End Performance 2021: Definiowanie środowiska

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Zróbmy 2021… szybko! Roczna lista kontrolna wydajności front-endu zawierająca wszystko, co musisz wiedzieć, aby tworzyć szybkie środowiska internetowe dzisiaj, od metryk po narzędzia i techniki front-endowe. Aktualizacja od 2016 roku.

Spis treści

  1. Przygotowanie: planowanie i metryki
  2. Wyznaczanie realistycznych celów
  3. Definiowanie środowiska
  4. Optymalizacje zasobów
  5. Optymalizacje kompilacji
  6. Optymalizacje dostawy
  7. Sieć, HTTP/2, HTTP/3
  8. Testowanie i monitorowanie
  9. Szybkie zwycięstwo
  10. Wszystko na jednej stronie
  11. Pobierz listę kontrolną (PDF, Apple Pages, MS Word)
  12. Zapisz się do naszego biuletynu e-mail, aby nie przegapić kolejnych przewodników.

Definiowanie środowiska

  1. Wybierz i skonfiguruj swoje narzędzia do budowania.
    Nie zwracaj zbytniej uwagi na to, co w dzisiejszych czasach podobno jest fajne. Trzymaj się swojego środowiska do budowania, czy to Grunt, Gulp, Webpack, Parcel, czy kombinację narzędzi. Dopóki uzyskujesz wyniki, których potrzebujesz i nie masz problemów z utrzymaniem procesu budowania, radzisz sobie dobrze.

    Wśród narzędzi do kompilacji Rollup zyskuje na popularności, podobnie jak Snowpack, ale Webpack wydaje się być najbardziej ugruntowanym, z dosłownie setkami dostępnych wtyczek do optymalizacji rozmiaru twoich kompilacji. Uważaj na Webpack Roadmap 2021.

    Jedną z najbardziej godnych uwagi strategii, która pojawiła się ostatnio, jest chunking granularny z pakietem Webpack w Next.js i Gatsby w celu zminimalizowania duplikowania kodu. Domyślnie moduły, które nie są współużytkowane w każdym punkcie wejścia, można żądać dla tras, które z niego nie korzystają. To kończy się obciążeniem, ponieważ pobieranych jest więcej kodu, niż jest to konieczne. Dzięki szczegółowemu dzieleniu fragmentów w Next.js możemy użyć pliku manifestu kompilacji po stronie serwera, aby określić, które wyjściowe fragmenty są używane przez różne punkty wejścia.

    Aby zredukować zduplikowany kod w projektach Webpack, możemy użyć granularnego chunkingu, domyślnie włączonej w Next.js i Gatsby
    Aby zredukować zduplikowany kod w projektach Webpack, możemy użyć granularnego chunkingu, domyślnie włączonej w Next.js i Gatsby. Źródło obrazu: Addy Osmani. (duży podgląd)

    Dzięki SplitChunksPlugin wiele podzielonych porcji jest tworzonych w zależności od wielu warunków, aby zapobiec pobieraniu zduplikowanego kodu na wielu trasach. Poprawia to czas ładowania strony i pamięć podręczną podczas nawigacji. Dostarczane w Next.js 9.2 i Gatsby v2.20.7.

    Rozpoczęcie korzystania z Webpack może być jednak trudne. Więc jeśli chcesz zagłębić się w Webpack, istnieje kilka świetnych zasobów:

    • Dokumentacja Webpack — oczywiście — jest dobrym punktem wyjścia, podobnie jak Webpack — The Confusing Bits autorstwa Raja Rao i An Annotated Webpack Config autorstwa Andrew Welcha.
    • Sean Larkin ma darmowy kurs na Webpack: The Core Concepts, a Jeffrey Way wydał fantastyczny darmowy kurs na Webpack dla każdego. Oba są świetnym wprowadzeniem do zanurzenia się w Webpack.
    • Webpack Fundamentals to bardzo obszerny 4-godzinny kurs z Seanem Larkinem, wydany przez FrontendMasters.
    • Przykładowe pakiety Webpack zawierają setki gotowych do użycia konfiguracji Webpacków, podzielonych na kategorie według tematu i celu. Bonus: istnieje również konfigurator konfiguracji Webpack, który generuje podstawowy plik konfiguracyjny.
    • awesome-webpack to wyselekcjonowana lista przydatnych zasobów, bibliotek i narzędzi Webpack, w tym artykułów, filmów, kursów, książek i przykładów dla projektów Angular, React i framework-agnostic.
    • Podróż do szybkiego budowania zasobów produkcyjnych za pomocą Webpack to studium przypadku Etsy dotyczące tego, jak zespół przeszedł z systemu kompilacji JavaScript opartego na RequireJS na korzystanie z Webpack i jak zoptymalizował swoje kompilacje, zarządzając ponad 13 200 zasobami średnio w 4 minuty .
    • Wskazówki dotyczące wydajności pakietu Webpack to wątek kopalni złota autorstwa Ivana Akulova, zawierający wiele wskazówek dotyczących wydajności, w tym te dotyczące konkretnie pakietu Webpack.
    • awesome-webpack-perf to repozytorium Goldmine GitHub z przydatnymi narzędziami Webpack i wtyczkami zwiększającymi wydajność. Utrzymywany również przez Ivana Akulova.
Wizualizacja podróży Etsy do szybkich kompilacji produkcyjnych z Webpack
Podróż Etsy do szybkich kompilacji produkcyjnych z Webpack (przez Addy Osmani) (duży podgląd)
  1. Użyj domyślnie stopniowego ulepszania.
    Mimo to, po tylu latach, utrzymanie progresywnego ulepszania jako naczelnej zasady architektury front-endu i wdrożenia jest bezpiecznym zakładem. Najpierw zaprojektuj i zbuduj podstawowe środowisko, a następnie ulepsz środowisko za pomocą zaawansowanych funkcji dla wydajnych przeglądarek, tworząc elastyczne środowiska. Jeśli Twoja witryna działa szybko na wolnym komputerze ze słabym ekranem w słabej przeglądarce w nieoptymalnej sieci, będzie działać szybciej tylko na szybkim komputerze z dobrą przeglądarką w przyzwoitej sieci.

    W rzeczywistości, z obsługą modułów adaptacyjnych, wydaje się, że przenosimy progresywne ulepszanie na wyższy poziom, udostępniając „lite” podstawowe doświadczenia urządzeniom z niższej półki i ulepszając je bardziej wyrafinowanymi funkcjami dla urządzeń z wyższej półki. Progresywne ulepszanie prawdopodobnie nie zniknie w najbliższym czasie.

  2. Wybierz solidną podstawę wydajności.
    Przy tak wielu niewiadomych wpływających na ładowanie — sieć, ograniczanie temperatury, wyrzucanie pamięci podręcznej, skrypty innych firm, wzorce blokowania parsera, we/wy dysku, opóźnienia IPC, zainstalowane rozszerzenia, oprogramowanie antywirusowe i zapory, zadania procesora w tle, ograniczenia sprzętowe i pamięciowe, różnice w buforowaniu L2/L3, RTTS — JavaScript jest najbardziej kosztowny, obok czcionek internetowych domyślnie blokujących renderowanie i obrazów często zużywających zbyt dużo pamięci. Ponieważ wąskie gardła wydajności przesuwają się z serwera na klienta, jako programiści, musimy rozważyć wszystkie te niewiadome bardziej szczegółowo.

    Mając budżet 170KB, który zawiera już ścieżkę krytyczną HTML/CSS/JavaScript, router, zarządzanie stanem, narzędzia, framework i logikę aplikacji, musimy dokładnie zbadać koszt transferu sieciowego, czas parsowania/kompilacji i koszt środowiska wykonawczego wybranych przez nas ram. Na szczęście w ciągu ostatnich kilku lat zauważyliśmy ogromną poprawę szybkości analizowania i kompilowania skryptów przez przeglądarki. Jednak wykonanie JavaScript jest nadal głównym wąskim gardłem, więc zwracanie szczególnej uwagi na czas wykonania skryptu i sieć może mieć wpływ.

    Tim Kadlec przeprowadził fantastyczne badania wydajności nowoczesnych frameworków i podsumował je w artykule „Struktury JavaScript mają swój koszt”. Często mówimy o wpływie samodzielnych frameworków, ale jak zauważa Tim, w praktyce często używa się wielu frameworków . Być może starsza wersja jQuery, która jest powoli migrowana do nowoczesnego frameworka, wraz z kilkoma starszymi aplikacjami korzystającymi ze starszej wersji Angulara. Dlatego bardziej rozsądne jest zbadanie skumulowanego kosztu bajtów JavaScript i czasu wykonywania procesora, które mogą łatwo sprawić, że doświadczenia użytkownika będą ledwo użyteczne, nawet na urządzeniach z najwyższej półki.

    Ogólnie rzecz biorąc, nowoczesne struktury nie traktują priorytetowo mniej wydajnych urządzeń , więc wrażenia na telefonie i na komputerze często będą się znacznie różnić pod względem wydajności. Według badań strony z Reactem lub Angularem spędzają więcej czasu na procesorze niż inne (co oczywiście niekoniecznie oznacza, że ​​React jest droższy na procesorze niż Vue.js).

    Według Tima jedna rzecz jest oczywista: „jeśli używasz frameworka do budowy swojej witryny, dokonujesz kompromisu pod względem początkowej wydajności — nawet w najlepszym scenariuszu”.

Koszt frameworków, czas procesora JavaScript: strony SPA działają słabo
Koszt frameworków, byes JavaScript: strony SPA (nadal) działają słabo
Skryptowanie czasu procesora związanego z urządzeniami mobilnymi i bajtów JavaScript dla urządzeń desktopv. Ogólnie strony z React lub Angular spędzają więcej czasu na procesorze niż inne. Ale to zależy od tego, jak zbudujesz witrynę. Badania Tima Kadleca. (duży podgląd)
  1. Oceń frameworki i zależności.
    Teraz nie każdy projekt potrzebuje frameworka i nie każda strona jednostronicowej aplikacji musi załadować framework. W przypadku Netflix „usunięcie Reacta, kilku bibliotek i odpowiedniego kodu aplikacji po stronie klienta zmniejszyło całkowitą ilość JavaScriptu o ponad 200 KB, powodując ponad 50% skrócenie czasu interakcji Netflix dla wylogowanej strony głównej ”. Następnie zespół wykorzystał czas spędzony przez użytkowników na stronie docelowej, aby wstępnie pobrać React dla kolejnych stron, na które użytkownicy prawdopodobnie trafią (szczegóły znajdziesz w dalszej części).

    A co, jeśli całkowicie usuniesz istniejący framework na krytycznych stronach? Dzięki Gatsby możesz sprawdzić gatsby-plugin-no-javascript, który usuwa wszystkie pliki JavaScript utworzone przez Gatsby ze statycznych plików HTML. W Vercel możesz także zezwolić na wyłączenie produkcyjnego JavaScriptu w czasie wykonywania dla niektórych stron (eksperymentalnie).

    Po wybraniu frameworka pozostaniemy przy nim przez co najmniej kilka lat, więc jeśli musimy go użyć, musimy upewnić się, że nasz wybór jest świadomy i dobrze przemyślany — dotyczy to zwłaszcza kluczowych wskaźników wydajności, które troszczyć się o.

    Dane pokazują, że domyślnie frameworki są dość drogie: 58,6% stron React dostarcza ponad 1 MB JavaScript, a 36% załadowanych stron Vue.js ma pierwsze wyrenderowanie treści trwające <1,5 s. Według badania przeprowadzonego przez Ankur Sethi „Twoja aplikacja React nigdy nie ładuje się szybciej niż około 1,1 sekundy na przeciętnym telefonie w Indiach, bez względu na to, jak bardzo ją zoptymalizujesz. Twoja aplikacja Angular zawsze będzie się uruchamiać co najmniej 2,7 sekundy. użytkownicy Twojej aplikacji Vue będą musieli poczekać co najmniej 1 sekundę, zanim będą mogli zacząć z niej korzystać”. Być może nie kierujesz reklam na Indie jako rynek podstawowy, ale użytkownicy uzyskujący dostęp do Twojej witryny o nieoptymalnych warunkach sieciowych będą mieli porównywalne wrażenia.

    Oczywiście możliwe jest szybkie tworzenie SPA, ale nie są one szybkie po wyjęciu z pudełka, więc musimy wziąć pod uwagę czas i wysiłek potrzebny do ich wykonania i utrzymania . Prawdopodobnie będzie łatwiej, wybierając na wczesnym etapie lekki podstawowy koszt wydajności.

    Jak więc wybrać framework ? Dobrym pomysłem jest rozważenie przynajmniej całkowitego kosztu rozmiaru + początkowego czasu realizacji przed wyborem opcji; lekkie opcje, takie jak Preact, Inferno, Vue, Svelte, Alpine lub Polymer, mogą dobrze wykonać zadanie. Rozmiar linii bazowej zdefiniuje ograniczenia dla kodu aplikacji.

    Jak zauważył Seb Markbage, dobrym sposobem na zmierzenie kosztów uruchomienia frameworków jest najpierw wyrenderowanie widoku, a następnie usunięcie go i ponowne renderowanie, ponieważ może on powiedzieć, jak skaluje się framework. Pierwsze renderowanie ma tendencję do rozgrzewania sporej ilości leniwie skompilowanego kodu, z którego może skorzystać większe drzewo, gdy się skaluje. Drugie renderowanie jest w zasadzie emulacją tego, jak ponowne użycie kodu na stronie wpływa na charakterystykę wydajności w miarę wzrostu złożoności strony.

    Możesz posunąć się nawet do oceny swoich kandydatów (lub ogólnie dowolnej biblioteki JavaScript) w 12-punktowym systemie punktacji Sacha Greif, badając funkcje, dostępność, stabilność, wydajność, ekosystem pakietów , społeczność, krzywą uczenia się, dokumentację, oprzyrządowanie, osiągnięcia , zespół, kompatybilność, np. bezpieczeństwo.

    Perf Track śledzi wydajność struktury na dużą skalę
    Perf Track śledzi wydajność struktury na dużą skalę. (duży podgląd)

    Możesz również polegać na danych gromadzonych w sieci przez dłuższy czas. Na przykład, Perf Track śledzi wydajność platformy na dużą skalę, pokazując zagregowane wyniki Core Web Vitals dla witryn zbudowanych w Angular, React, Vue, Polymer, Preact, Ember, Svelte i AMP. Możesz nawet określić i porównać strony internetowe zbudowane za pomocą Gatsby, Next.js lub Create React App, a także strony zbudowane za pomocą Nuxt.js (Vue) lub Sapper (Svelte).

    Dobrym punktem wyjścia jest wybór dobrego domyślnego stosu dla twojej aplikacji. Gatsby (React), Next.js (React), Vuepress (Vue), Preact CLI i PWA Starter Kit zapewniają rozsądne ustawienia domyślne do szybkiego ładowania po wyjęciu z pudełka na przeciętnym sprzęcie mobilnym. ​​Również spójrz na wytyczne dotyczące wydajności dla frameworków web.dev dla React i Angular ( dzięki, Phillip! ).

    I być może mógłbyś przyjąć nieco bardziej odświeżające podejście do tworzenia aplikacji jednostronicowych — Turbolinks, 15-KB biblioteka JavaScript, która używa HTML zamiast JSON do renderowania widoków. Tak więc, gdy podążasz za linkiem, Turbolinks automatycznie pobiera stronę, zamienia <body> i łączy <head> , a wszystko to bez ponoszenia kosztów pełnego załadowania strony. Możesz sprawdzić szybkie szczegóły i pełną dokumentację dotyczącą stosu (Hotwire).

Wykres przypominający histogram przedstawiający wydajność obliczeniową najlepiej sprzedających się telefonów
Wydajność procesora i mocy obliczeniowej najlepiej sprzedających się telefonów (Źródło zdjęcia: Addy Osmani) (duży podgląd)
  1. Renderowanie po stronie klienta czy renderowanie po stronie serwera? Obie!
    To dość gorąca rozmowa. Ostatecznym podejściem byłoby skonfigurowanie pewnego rodzaju progresywnego uruchamiania: użyj renderowania po stronie serwera, aby uzyskać szybkie pierwsze wyrenderowanie treści, ale także dodaj trochę niezbędnego JavaScript, aby utrzymać czas do interakcji bliski Pierwszemu wyrenderowaniu treści. Jeśli JavaScript pojawi się zbyt późno po FCP, przeglądarka zablokuje główny wątek podczas analizowania, kompilowania i wykonywania późno odkrytego JavaScriptu, ograniczając w ten sposób interaktywność witryny lub aplikacji.

    Aby tego uniknąć, zawsze dziel wykonywanie funkcji na oddzielne, asynchroniczne zadania i tam, gdzie to możliwe, używaj requestIdleCallback . Rozważ leniwe ładowanie części interfejsu użytkownika za pomocą dynamicznej obsługi import() w WebPack, unikając obciążenia, analizowania i kompilowania kosztów, dopóki użytkownicy naprawdę ich nie potrzebują ( dzięki Addy! ).

    Jak wspomniano powyżej, Time to Interactive (TTI) informuje nas o czasie między nawigacją a interaktywnością. W szczegółach metryka jest definiowana przez spojrzenie na pierwsze pięciosekundowe okno po wyrenderowaniu początkowej zawartości, w którym żadne zadania JavaScript nie trwają dłużej niż 50 ms ( Long Tasks ). Jeśli wystąpi zadanie trwające ponad 50 ms, wyszukiwanie pięciosekundowego okna rozpoczyna się od nowa. W rezultacie przeglądarka najpierw założy, że dotarła do Interactive , tylko po to, by przełączyć się na Frozen , by ostatecznie przełączyć się z powrotem na Interactive .

    Gdy dotarliśmy do Interactive , możemy — na żądanie lub w miarę czasu — uruchomić mniej istotne części aplikacji. Niestety, jak zauważył Paul Lewis, frameworki zazwyczaj nie mają prostego pojęcia priorytetu, który można przedstawić programistom, a zatem progresywne uruchamianie nie jest łatwe do zaimplementowania w większości bibliotek i frameworków.

    A jednak do tego dochodzimy. Obecnie istnieje kilka możliwości, które możemy zbadać, a Houssein Djirdeh i Jason Miller zapewniają doskonały przegląd tych opcji w swoim przemówieniu na temat Renderowania w sieci oraz w artykule Jasona i Addy'ego na temat nowoczesnych architektur frontonu. Poniższy przegląd opiera się na ich gwiezdnej pracy.

    • Pełne renderowanie po stronie serwera (SSR)
      W klasycznym SSR, takim jak WordPress, wszystkie żądania są obsługiwane w całości na serwerze. Żądana treść jest zwracana jako gotowa strona HTML, a przeglądarki mogą ją od razu renderować. W związku z tym aplikacje SSR nie mogą tak naprawdę korzystać na przykład z interfejsów API DOM. Różnica między First Contentful Paint a Time to Interactive jest zwykle niewielka, a strona może być renderowana od razu, gdy HTML jest przesyłany strumieniowo do przeglądarki.

      Pozwala to uniknąć dodatkowych podróży w obie strony w celu pobierania danych i tworzenia szablonów na kliencie, ponieważ jest to obsługiwane, zanim przeglądarka otrzyma odpowiedź. Jednak kończy się to dłuższym czasem myślenia serwera, a co za tym idzie Time To First Byte i nie korzystamy z responsywnych i bogatych funkcji nowoczesnych aplikacji.

    • Renderowanie statyczne
      Tworzymy produkt jako aplikację jednostronicową, ale wszystkie strony są wstępnie renderowane do statycznego kodu HTML z minimalnym kodem JavaScript jako etapem tworzenia. Oznacza to, że przy statycznym renderowaniu tworzymy z wyprzedzeniem indywidualne pliki HTML dla każdego możliwego adresu URL , na co nie może sobie pozwolić wiele aplikacji. Ale ponieważ kod HTML strony nie musi być generowany w locie, możemy osiągnąć niezmiennie szybki czas do pierwszego bajtu. W ten sposób możemy szybko wyświetlić stronę docelową, a następnie wstępnie pobrać szkielet SPA dla kolejnych stron. Netflix zastosował to podejście, zmniejszając ładowanie i czas do interakcji o 50%.

    • Renderowanie po stronie serwera z (re)hydratacją (renderowanie uniwersalne, SSR + CSR)
      Możemy spróbować wykorzystać to, co najlepsze z obu światów — podejścia SSR i CSR. Z uwodnieniem w mieszance, strona HTML zwrócona z serwera zawiera również skrypt, który ładuje w pełni rozwiniętą aplikację po stronie klienta. Idealnie, aby osiągnąć szybkie pierwsze wyrenderowanie treści (takie jak SSR), a następnie kontynuować renderowanie z (ponownym) nawodnieniem. Niestety rzadko tak się dzieje. Częściej strona wygląda na gotową, ale nie odpowiada na wpisy użytkownika, powodując wściekłość i porzucenia.

      Dzięki React możemy użyć modułu ReactDOMServer na serwerze Node, takim jak Express, a następnie wywołać metodę renderToString , aby wyrenderować komponenty najwyższego poziomu jako statyczny ciąg HTML.

      Dzięki Vue.js możemy użyć vue-server-renderer do renderowania instancji Vue do HTML za pomocą renderToString . W Angularze możemy użyć @nguniversal do przekształcenia żądań klienta w strony HTML w pełni renderowane przez serwer. W pełni renderowane na serwerze doświadczenie można również uzyskać po wyjęciu z pudełka za pomocą Next.js (React) lub Nuxt.js (Vue).

      To podejście ma swoje wady. W rezultacie zyskujemy pełną elastyczność aplikacji po stronie klienta, zapewniając jednocześnie szybsze renderowanie po stronie serwera, ale kończy się to również dłuższą przerwą między First Contentful Paint i Time To Interactive oraz zwiększonym opóźnieniem pierwszego wejścia. Nawodnienie jest bardzo drogie i zwykle sama ta strategia nie wystarczy, ponieważ znacznie opóźnia Time To Interactive.

    • Renderowanie strumieniowe po stronie serwera z progresywnym nawodnieniem (SSR + CSR)
      Aby zminimalizować lukę między Time To Interactive a First Contentful Paint, renderujemy wiele żądań jednocześnie i wysyłamy zawartość porcjami w miarę ich generowania. Nie musimy więc czekać na pełny ciąg kodu HTML przed wysłaniem treści do przeglądarki, a tym samym ulepszamy Time To First Byte.

      W React, zamiast renderToString() , możemy użyć renderToNodeStream() do potoku odpowiedzi i wysłania kodu HTML w kawałkach. W Vue możemy użyć renderToStream(), które można przesyłać potokowo i przesyłać strumieniowo. Dzięki React Suspense możemy również w tym celu użyć renderowania asynchronicznego.

      Po stronie klienta, zamiast uruchamiać całą aplikację naraz, uruchamiamy komponenty stopniowo . Sekcje aplikacji są najpierw dzielone na samodzielne skrypty z podziałem kodu, a następnie stopniowo uwadniane (w kolejności naszych priorytetów). W rzeczywistości możemy najpierw nawodnić kluczowe składniki, podczas gdy resztę można nawodnić później. Rolę renderowania po stronie klienta i po stronie serwera można następnie zdefiniować w różny sposób dla poszczególnych komponentów. Możemy wtedy również odroczyć uwodnienie niektórych komponentów, dopóki nie pojawią się one w widoku lub będą potrzebne do interakcji użytkownika lub gdy przeglądarka jest bezczynna.

      Dla Vue Markus Oberlehner opublikował przewodnik na temat skrócenia Time To Interactive aplikacji SSR za pomocą uwodnienia interakcji użytkownika, a także vue-lazy-hydration, wtyczki na wczesnym etapie, która umożliwia uwodnienie komponentów w przypadku widoczności lub określonej interakcji użytkownika. Zespół Angular pracuje nad progresywnym nawodnieniem z Ivy Universal. Częściowe nawodnienie można również wdrożyć za pomocą Preact i Next.js.

    • Renderowanie trizomorficzne
      Mając wdrożone procesy robocze, możemy użyć renderowania serwera przesyłania strumieniowego dla nawigacji początkowych/nie JS, a następnie, po zainstalowaniu, pracownik usługowy zajmie się renderowaniem kodu HTML dla nawigacji. W takim przypadku Service Worker wstępnie renderuje zawartość i włącza nawigacje w stylu SPA w celu renderowania nowych widoków w tej samej sesji. Działa dobrze, gdy możesz współużytkować ten sam kod szablonów i routingu między serwerem, stroną klienta i procesem Service Worker.

    Ilustracja pokazująca, jak działa renderowanie trizomorficzne w 3 miejscach, takich jak renderowanie DOM, wstępne renderowanie Service Worker i renderowanie po stronie serwera
    Renderowanie trizomorficzne, z tym samym renderowaniem kodu w dowolnych 3 miejscach: na serwerze, w DOM lub w service workerze. (źródło obrazu: Google Developers) (duży podgląd)
    • CSR z prerenderowaniem
      Wstępne renderowanie jest podobne do renderowania po stronie serwera, ale zamiast dynamicznie renderować strony na serwerze, renderujemy aplikację do statycznego kodu HTML w czasie kompilacji. Chociaż strony statyczne są w pełni interaktywne i nie zawierają dużo kodu JavaScript po stronie klienta, wstępne renderowanie działa inaczej . Zasadniczo przechwytuje początkowy stan aplikacji po stronie klienta jako statyczny HTML w czasie kompilacji, podczas gdy z prerenderowaniem aplikacja musi zostać uruchomiona na kliencie, aby strony były interaktywne.

      Dzięki Next.js możemy użyć statycznego eksportu HTML, wstępnie renderując aplikację do statycznego HTML. W Gatsby, generatorze witryn statycznych typu open source, który korzysta z React, podczas kompilacji używa metody renderToStaticMarkup zamiast metody renderToString , przy czym główny fragment JS jest wstępnie ładowany, a przyszłe trasy są wstępnie pobierane, bez atrybutów DOM, które nie są potrzebne w przypadku prostych stron statycznych.

      W przypadku Vue możemy wykorzystać Vuepress do osiągnięcia tego samego celu. Możesz także użyć prerender-loadera z Webpackiem. Navi zapewnia również renderowanie statyczne.

      Rezultatem jest lepsze wyrenderowanie czasu do pierwszego bajtu i pierwsze wyrenderowanie treści, a także zmniejszamy lukę między wyrenderowaniem czasu do interaktywnego a pierwszym wyrenderowaniem treści. Nie możemy zastosować tego podejścia, jeśli oczekuje się, że zawartość zmieni się znacznie. Ponadto wszystkie adresy URL muszą być znane z wyprzedzeniem, aby wygenerować wszystkie strony. Tak więc niektóre komponenty mogą być renderowane za pomocą renderowania wstępnego, ale jeśli potrzebujemy czegoś dynamicznego, musimy polegać na aplikacji, aby pobrać zawartość.

    • Pełne renderowanie po stronie klienta (CSR)
      Cała logika, renderowanie i uruchamianie są wykonywane na kliencie. Rezultatem jest zwykle ogromna luka między Time To Interactive a First Contentful Paint. W rezultacie aplikacje często działają wolno, ponieważ cała aplikacja musi zostać uruchomiona na kliencie, aby cokolwiek renderować.

      Ponieważ JavaScript wiąże się z kosztami wydajności, wraz ze wzrostem ilości JavaScriptu wraz z aplikacją, agresywne dzielenie kodu i odkładanie kodu JavaScript będzie absolutnie konieczne, aby okiełznać wpływ JavaScriptu. W takich przypadkach renderowanie po stronie serwera jest zwykle lepszym podejściem, jeśli nie jest wymagana duża interaktywność. Jeśli nie jest to możliwe, rozważ użycie modelu powłoki aplikacji.

      Ogólnie rzecz biorąc, SSR jest szybszy niż CSR. Jednak nadal jest to dość częsta implementacja dla wielu aplikacji.

    A więc po stronie klienta czy po stronie serwera? Ogólnie rzecz biorąc, dobrym pomysłem jest ograniczenie korzystania z frameworków w pełni po stronie klienta do stron, które absolutnie ich wymagają. W przypadku zaawansowanych aplikacji nie jest dobrym pomysłem poleganie wyłącznie na renderowaniu po stronie serwera. Zarówno renderowanie przez serwer, jak i renderowanie przez klienta jest katastrofą, jeśli zostanie wykonane źle.

    Niezależnie od tego, czy skłaniasz się ku CSR, czy SSR, upewnij się, że renderujesz ważne piksele tak szybko, jak to możliwe i minimalizuj lukę między tym renderowaniem a Time To Interactive. Rozważ wstępne renderowanie, jeśli Twoje strony nie zmieniają się zbytnio, i opóźnij uruchamianie frameworków, jeśli możesz. Przesyłaj strumieniowo HTML w kawałkach z renderowaniem po stronie serwera i wdrażaj progresywne nawadnianie renderowania po stronie klienta — i koncentruj się na widoczności, interakcji lub w czasie bezczynności, aby uzyskać to, co najlepsze z obu światów.

Tabela porównująca opcje renderowania po stronie klienta i po stronie serwera
Spektrum opcji renderowania po stronie klienta i renderowania po stronie serwera. Zobacz także wykład Jasona i Housseina na Google I/O na temat implikacji wydajności architektury aplikacji. (Źródło obrazu: Jason Miller) (duży podgląd)
Przykład strony internetowej AirBnB pokazującej bez progresywnego nawodnienia po lewej stronie i z progresywnym nawodnieniem po prawej
AirBnB eksperymentuje z progresywnym nawodnieniem; odkładają niepotrzebne komponenty, obciążają interakcję użytkownika (przewijanie) lub w czasie bezczynności, a testy pokazują, że może to poprawić TTI. (duży podgląd)
  1. Ile możemy podać statycznie?
    Niezależnie od tego, czy pracujesz nad dużą aplikacją, czy małą witryną, warto zastanowić się, jaka zawartość może być serwowana statycznie z CDN (tj. JAM Stack), a nie generowana dynamicznie w locie. Nawet jeśli masz tysiące produktów i setki filtrów z mnóstwem opcji personalizacji, nadal możesz chcieć wyświetlać krytyczne strony docelowe w sposób statyczny i oddzielić te strony od wybranych przez siebie ram.

    Istnieje wiele generatorów witryn statycznych, a generowane przez nie strony są często bardzo szybkie. Im więcej treści możemy wstępnie zbudować z wyprzedzeniem, zamiast generować odsłony na serwerze lub kliencie w czasie żądania, tym lepszą wydajność osiągniemy.

    W Budowaniu częściowo uwodnionych, progresywnie ulepszanych statycznych stron internetowych Markus Oberlehner pokazuje, jak tworzyć strony internetowe za pomocą generatora stron statycznych i SPA, jednocześnie osiągając progresywne ulepszanie i minimalny rozmiar pakietu JavaScript. Markus używa Eleveny i Preact jako swoich narzędzi i pokazuje, jak skonfigurować narzędzia, dodać częściowe nawodnienie, leniwe nawodnienie, plik wejściowy klienta, skonfigurować Babel dla Preact i łączyć Preact z Rollupem — od początku do końca.

    W dzisiejszych czasach, gdy JAMStack jest używany w dużych witrynach, pojawiła się nowa kwestia dotycząca wydajności: czas kompilacji . W rzeczywistości budowanie nawet tysięcy stron przy każdym nowym wdrożeniu może zająć kilka minut, więc obiecujące jest, że w Gatsby pojawią się przyrostowe kompilacje, które skracają czas tworzenia o 60 razy , dzięki integracji z popularnymi rozwiązaniami CMS, takimi jak WordPress, Contentful, Drupal, Netlify CMS i inni.

    Schemat blokowy przedstawiający Użytkownika 1 w lewym górnym rogu i Użytkownika 2 w lewym dolnym rogu, przedstawiający proces przyrostowego odtwarzania statusu
    Przyrostowa regeneracja statyczna z Next.js. (Źródło zdjęcia: Prisma.io) (duży podgląd)

    Ponadto Next.js ogłosił wyprzedzające i przyrostowe generowanie statycznych, co pozwala nam dodawać nowe strony statyczne w czasie wykonywania i aktualizować istniejące strony po ich zbudowaniu, ponownie renderując je w tle w miarę napływu ruchu .

    Potrzebujesz jeszcze lżejszego podejścia? W swoim przemówieniu na temat Eleveny, Alpine i Tailwind: w kierunku lekkiego Jamstack, Nicola Goutay wyjaśnia różnice między CSR, SSR i wszystkim pomiędzy i pokazuje, jak zastosować bardziej lekkie podejście — wraz z repozytorium GitHub, które pokazuje to podejście w praktyce.

  2. Rozważ użycie wzorca PRPL i architektury powłoki aplikacji.
    Różne frameworki będą miały różny wpływ na wydajność i będą wymagały różnych strategii optymalizacji, więc musisz jasno zrozumieć wszystkie zalety frameworka, na którym będziesz polegać. Tworząc aplikację internetową, spójrz na wzorzec PRPL i architekturę powłoki aplikacji. Pomysł jest całkiem prosty: należy umieścić minimalny kod potrzebny do uzyskania interaktywności w celu szybkiego renderowania początkowej trasy, a następnie użyć narzędzia Service Worker do buforowania i wstępnego buforowania zasobów, a następnie asynchronicznie ładować potrzebne trasy z leniwym ładowaniem.
Wzorzec PRPL w architekturze powłoki aplikacji
PRPL oznacza wypychanie krytycznych zasobów, renderowanie początkowej trasy, wstępne buforowanie pozostałych tras i leniwe ładowanie pozostałych tras na żądanie.
Architektura powłoki aplikacji
Powłoka aplikacji to minimalny kod HTML, CSS i JavaScript obsługujący interfejs użytkownika.
  1. Czy zoptymalizowałeś wydajność swoich interfejsów API?
    Interfejsy API to kanały komunikacji aplikacji umożliwiające udostępnianie danych aplikacjom wewnętrznym i zewnętrznym za pośrednictwem punktów końcowych . Projektując i budując API, potrzebujemy rozsądnego protokołu, aby umożliwić komunikację między serwerem a żądaniami stron trzecich. Representational State Transfer ( REST ) ​​to dobrze ugruntowany, logiczny wybór: definiuje zestaw ograniczeń, których przestrzegają programiści, aby zawartość była dostępna w wydajny, niezawodny i skalowalny sposób. Usługi sieci Web zgodne z ograniczeniami REST są nazywane usługami sieciowymi zgodnymi z REST .

    Podobnie jak w przypadku starych, dobrych żądań HTTP, gdy dane są pobierane z interfejsu API, wszelkie opóźnienia w odpowiedzi serwera będą rozchodzić się na użytkownika końcowego, opóźniając renderowanie . Gdy zasób chce pobrać niektóre dane z interfejsu API, będzie musiał zażądać danych z odpowiedniego punktu końcowego. Komponent, który renderuje dane z kilku zasobów, na przykład artykuł z komentarzami i zdjęciami autora w każdym komentarzu, może wymagać kilku podróży w obie strony do serwera w celu pobrania wszystkich danych przed ich renderowaniem. Co więcej, ilość danych zwracanych przez REST często przekracza ilość potrzebną do renderowania tego komponentu.

    Jeśli wiele zasobów wymaga danych z interfejsu API, interfejs API może stać się wąskim gardłem wydajności. GraphQL zapewnia wydajne rozwiązanie tych problemów. GraphQL sam w sobie jest językiem zapytań dla Twojego interfejsu API i środowiskiem wykonawczym po stronie serwera do wykonywania zapytań przy użyciu systemu typów, który definiujesz dla swoich danych. W przeciwieństwie do REST, GraphQL może pobrać wszystkie dane w jednym żądaniu , a odpowiedź będzie dokładnie taka, jaka jest wymagana, bez nadmiernego lub niedostatecznego pobierania danych, jak to zwykle ma miejsce w przypadku REST.

    Ponadto, ponieważ GraphQL korzysta ze schematu (metadanych, które mówią o strukturze danych), może już organizować dane w preferowaną strukturę, więc na przykład za pomocą GraphQL możemy usunąć kod JavaScript używany do zarządzania stanem, produkcji czystszy kod aplikacji, który działa szybciej na kliencie.

    Jeśli chcesz rozpocząć pracę z GraphQL lub napotkać problemy z wydajnością, te artykuły mogą być bardzo pomocne:

    • GraphQL Primer: Dlaczego potrzebujemy nowego rodzaju interfejsu API autorstwa Erica Baera,
    • GraphQL Primer: ewolucja projektowania API autorstwa Erica Baera,
    • Zaprojektowanie serwera GraphQL pod kątem optymalnej wydajności przez Leonardo Losoviza,
    • Działanie GraphQL wyjaśnione przez Wojciecha Trockiego.
Dwa przykłady interfejsów mobilnych dla komunikatów podczas korzystania z Redux/REST (po lewej) i Apollo/GraphQL (po prawej)
Różnica między REST a GraphQL, zilustrowana konwersacją między Redux + REST po lewej, a Apollo + GraphQL po prawej. (Źródło obrazu: Hacker Noon) (duży podgląd)
  1. Będziesz używać AMP czy artykułów błyskawicznych?
    W zależności od priorytetów i strategii Twojej organizacji, możesz rozważyć skorzystanie z AMP Google, artykułów błyskawicznych na Facebooku lub Apple News. Możesz bez nich osiągnąć dobrą wydajność, ale AMP zapewnia solidne ramy wydajności z darmową siecią dostarczania treści (CDN), podczas gdy artykuły błyskawiczne zwiększą Twoją widoczność i wydajność na Facebooku.

    Pozornie oczywistą zaletą tych technologii dla użytkowników jest gwarantowana wydajność , więc czasami mogą nawet preferować linki AMP-/Apple News/Instant Pages od „zwykłych” i potencjalnie nadętych stron. W przypadku witryn z dużą ilością treści, które mają do czynienia z dużą ilością treści stron trzecich, opcje te mogą potencjalnie znacznie przyspieszyć czas renderowania.

    Chyba że nie. Według Tima Kadleca, na przykład, „Dokumenty AMP są zwykle szybsze niż ich odpowiedniki, ale niekoniecznie oznaczają, że strona jest wydajna. AMP nie jest tym, co robi największą różnicę z punktu widzenia wydajności”.

    Korzyść dla właściciela strony jest oczywista: wykrywalność tych formatów na odpowiednich platformach i zwiększona widoczność w wyszukiwarkach.

    Cóż, przynajmniej tak było kiedyś. Ponieważ AMP nie jest już wymagany w przypadku najważniejszych artykułów , wydawcy mogą zamiast tego przenosić się z AMP na tradycyjny stos ( dzięki, Barry! ).

    Mimo to możesz również tworzyć progresywne internetowe AMP, ponownie wykorzystując AMP jako źródło danych dla swojego PWA. Wadą? Oczywiście obecność w otoczonym murem ogrodzie daje programistom możliwość produkowania i utrzymywania oddzielnej wersji swoich treści, a w przypadku Instant Article i Apple News bez faktycznych adresów URL (dzięki Addy, Jeremy!) .

  2. Wybierz swój CDN mądrze.
    Jak wspomniano powyżej, w zależności od tego, ile masz danych dynamicznych, możesz „zlecić” część zawartości statycznemu generatorowi witryn, przesyłając ją do CDN i udostępniając z niej statyczną wersję, unikając w ten sposób żądań do serwer. W rzeczywistości niektóre z tych generatorów są w rzeczywistości kompilatorami stron internetowych z wieloma automatycznymi optymalizacjami dostarczanymi po wyjęciu z pudełka. Ponieważ kompilatory z czasem dodają optymalizacje, skompilowane dane wyjściowe stają się z czasem mniejsze i szybsze.

    Zwróć uwagę, że sieci CDN mogą również udostępniać (i odciążać) zawartość dynamiczną. Tak więc ograniczanie CDN do zasobów statycznych nie jest konieczne. Sprawdź dokładnie, czy Twój CDN wykonuje kompresję i konwersję (np. optymalizację obrazu i zmianę rozmiaru na brzegu), czy zapewnia wsparcie dla pracowników serwerów, testy A/B, a także dołączanie po stronie brzegowej, które montuje statyczne i dynamiczne części stron na krawędzi CDN (tj. serwer najbliżej użytkownika) i inne zadania. Sprawdź również, czy Twój CDN obsługuje HTTP przez QUIC (HTTP/3).

    Katie Hempenius napisała fantastyczny przewodnik po sieciach CDN, który zawiera informacje o tym, jak wybrać dobrą sieć CDN , jak ją dostroić i o wszystkich drobiazgach, o których należy pamiętać podczas oceny jednego z nich. Ogólnie rzecz biorąc, dobrym pomysłem jest buforowanie zawartości tak agresywnie, jak to możliwe i włączenie funkcji wydajności CDN, takich jak Brotli, TLS 1.3, HTTP/2 i HTTP/3.

    Uwaga : na podstawie badań przeprowadzonych przez Patricka Meenana i Andy'ego Daviesa priorytetyzacja HTTP/2 jest skutecznie łamana w wielu sieciach CDN, więc należy zachować ostrożność przy wyborze sieci CDN. Patrick ma więcej szczegółów w swoim przemówieniu na temat priorytetyzacji HTTP/2 ( dzięki Barry! ).

    CDNPerf podgląd nazw CDN i szybkość zapytań w ms
    CDNPerf mierzy szybkość zapytań dla sieci CDN, zbierając i analizując 300 milionów testów każdego dnia. (duży podgląd)

    Wybierając CDN, możesz skorzystać z tych witryn porównawczych ze szczegółowym przeglądem ich funkcji:

    • Porównanie CDN, macierz porównania CDN dla Cloudfront, Aazure, KeyCDN, Fastly, Verizon, Stackpach, Akamai i wielu innych.
    • CDN Perf mierzy szybkość zapytań dla sieci CDN, zbierając i analizując 300 milionów testów każdego dnia, a wszystkie wyniki są oparte na danych RUM od użytkowników z całego świata. Sprawdź także porównanie wydajności DNS i porównanie wydajności chmury.
    • CDN Planet Guides zawiera przegląd sieci CDN dla określonych tematów, takich jak Serve Nieaktualne, Oczyszczanie, Origin Shield, Prefetch i Compression.
    • Web Almanach: Adopcja i użytkowanie CDN zapewnia wgląd w najlepszych dostawców CDN, ich zarządzanie RTT i TLS, czas negocjacji TLS, adopcję HTTP/2 i inne. (Niestety dane pochodzą tylko z 2019 r.).

Spis treści

  1. Przygotowanie: planowanie i metryki
  2. Wyznaczanie realistycznych celów
  3. Definiowanie środowiska
  4. Optymalizacje zasobów
  5. Optymalizacje kompilacji
  6. Optymalizacje dostawy
  7. Sieć, HTTP/2, HTTP/3
  8. Testowanie i monitorowanie
  9. Szybkie zwycięstwo
  10. Wszystko na jednej stronie
  11. Pobierz listę kontrolną (PDF, Apple Pages, MS Word)
  12. Zapisz się do naszego biuletynu e-mail, aby nie przegapić kolejnych przewodników.