Blog inżynierski web.dev nr 1: jak tworzymy witrynę i korzystamy z komponentów sieciowych

To pierwszy post na blogu inżynierskim web.dev. Mamy nadzieję, że w nadchodzących miesiącach będziemy udostępniać przydatne statystyki na temat naszej pracy. Dlatego zachęcamy do zaglądania na posty z tagiem na blogu dla inżynierów. Tutaj omówimy proces tworzenia witryny statycznej oraz (opcjonalnie) za komponentami internetowymi.

Na web.dev znajdziesz treści na temat tworzenia nowoczesnych stron internetowych oraz informacje o tym, jak mierzyć wydajność witryny. Doświadczeni użytkownicy mogli już wiedzieć, że nasza strona wskaźnika to tylko interfejs dla Lighthouse, który jest też dostępny w Narzędziach deweloperskich w Chrome. Po zalogowaniu się na stronie web.dev możesz regularnie przeprowadzać audyty Lighthouse w Twojej witrynie i sprawdzać, jak ich wynik zmienia się z czasem. Jeszcze raz odwiedzę stronę Wskaźnik, ponieważ wydaje nam się, że jest doskonała. 🎊

Wstęp

Zasadniczo web.dev to witryna statyczna generowana na podstawie zbioru plików Markdown. Wybraliśmy Eleventy, ponieważ jest to eleganckie i elastyczne narzędzie, które ułatwia przekształcanie formatu Markdown w HTML.

Używamy też nowoczesnych pakietów JavaScript, które udostępniamy tylko w przeglądarkach obsługujących type="module", w tym async i await. Korzystamy też z funkcji, które są obsługiwane przez zawsze aktualne przeglądarki, ale nie przez większość starszych wersji. Ponieważ jesteśmy witryną statyczną, do odczytywania naszych treści nie jest wymagany JavaScript.

Po zakończeniu procesu kompilacji, który obejmuje generowanie statycznego kodu HTML i łączenie kodu JavaScript z funkcją o pełnym zakresie, witrynę web.dev można hostować na potrzeby testów za pomocą prostego serwera statycznego. Witryna jest prawie całkowicie statyczna, ale mamy kilka szczególnych potrzeb, które nadal mogą być przydatne dzięki niestandardowemu serwerowi Node.js. Obejmują one przekierowania do nieprawidłowych domen, a także kod analizujący preferowany język użytkownika na potrzeby nadchodzącej funkcji internacjonalizacji.

Generowanie statyczne

Każda strona w web.dev jest napisana w języku Markdown. Wszystkie strony zawierają atrybut front Matter, który opisuje metadane każdego posta. Metadane są przetwarzane w układzie każdej strony i tworzą nagłówki, tagi itp. Oto przykład:

---
layout: post
title: What is network reliability and how do you measure it?
authors:
  - jeffposnick
date: 2018-11-05
description: |
  The modern web is enjoyed by a wide swath of people…
---

The modern web is enjoyed by a wide swath of [people](https://www.youtube.com/watch?v=dQw4w9WgXcQ), using a range of different devices and types of network connections.

Your creations can reach users all across the world...

Umożliwia ona definiowanie dowolnych właściwości, takich jak autorzy, data publikacji i tagi. Eleventy w wygodny sposób prezentuje interfejs użytkownika jako dane w niemal każdej wtyczce, szablonie i innym kontekście, w którym chcemy uzyskać inteligentne funkcje. Obiekt danych zawiera też to, co w Eleventy określa jako kaskadę danych, czyli różne dane pobierane z poszczególnych stron, z układu, z którego korzysta strona, oraz z danych znajdujących się w hierarchicznej strukturze folderów.

Każdy z nich opisuje inny typ treści i może dziedziczyć go z innych układów. W witrynie web.dev używamy tej funkcji, aby prawidłowo umieszczać w ramkach różne typy treści (np. posty i ćwiczenia z programowania), a jednocześnie udostępniać jeden układ HTML najwyższego poziomu.

Kolekcje

Eleventy umożliwia automatyczne tworzenie dowolnych kolekcji treści. Dzięki temu mogliśmy dzielić się na strony i generować strony wirtualne (czyli takie, które nie mają na dysku pasującego pliku Markdown) dla autorów postów. Strony naszych autorów tworzymy na przykład przy użyciu szablonu zawierającego wyrażenie odpowiadające jego linkowi bezpośredniemu (dzięki czemu szablon jest ponownie renderowany dla każdego autora) oraz zapasowej kolekcji.

W ten sposób powstanie na przykład prosta strona ze wszystkimi postami Ady.

Ograniczenia

Obecnie nie możemy łatwo przystosować się do procesu tworzenia w Eleventy, ponieważ ma on charakter deklaratywny, a nie imperatywny – zamiast tego opisujesz, co chcesz, a nie jak. Uruchomienie Eleventy jako części większego narzędzia do kompilacji jest trudne, ponieważ można je wywołać tylko z poziomu interfejsu wiersza poleceń.

Tworzenie szablonów

web.dev korzysta z systemu szablonów Nunjucks, który został pierwotnie opracowany przez Mozilla. Nunjucks udostępnia typowe funkcje szablonów, takie jak pętle i warunki warunkowe, ale umożliwia też definiowanie krótkich kodów, które generują dodatkowy kod HTML lub wywołują inne funkcje logiczne.

Podobnie jak w przypadku większości zespołów tworzących strony statyczne, zaczynaliśmy od małych projektów i z czasem dodajemy krótkie kody – jak dotąd było ich około 20. Większość z nich po prostu generuje dodatkowy kod HTML (w tym nasze niestandardowe komponenty sieciowe). Oto przykład:

{% Aside %}
See how Asides work in the web.dev codebase
{% endAside %}

Będzie on wyglądał tak:

Ale w rzeczywistości tworzony jest kod HTML, który wygląda tak:

<div class="aside color-state-info-text">
<p>See how Asides work in the web.dev codebase</p>
</div>

Nie omówiliśmy już tego postu, ale web.dev korzysta też ze skrótów jako języka metaprogramowania. Krótkie kody akceptują argumenty, a jednym z nich jest treść. Skrócone kody nie muszą zwracać żadnych informacji, więc można ich używać do tworzenia stanu i wywoływania innych działań. 🤔💭

Tworzenie scenariusza

Jak już wspomnieliśmy, witryna web.dev jest witryną statyczną, więc może być wyświetlana i używana bez JavaScriptu oraz przez starsze przeglądarki, które nie obsługują type="module" ani innego nowoczesnego kodu. To niezwykle ważny element naszego podejścia do udostępniania witryny web.dev wszystkim użytkownikom.

Nasz kod na potrzeby nowoczesnych przeglądarek składa się jednak z 2 głównych części:

  1. Kod wczytywania, który zawiera kod stanu globalnego, Analytics i routingu SPA
  2. Kod i CSS dla komponentów sieciowych, które stopniowo ulepszają witrynę

Kod wczytywania jest dość prosty: web.dev może wczytywać nowe strony jako aplikację jednostronicową (SPA), więc instalujemy globalny detektor, który rejestruje kliknięcia lokalnych elementów <a href="...">. Model SPA pomaga nam utrzymać globalny stan bieżącej sesji użytkownika, ponieważ w przeciwnym razie każde nowe wczytanie strony spowodowałoby wywołanie Firebase w celu uzyskania dostępu do stanu zalogowania użytkownika.

Wskazujemy również kilka różnych punktów wejścia w witrynie, w zależności od klikniętego adresu URL, i wczytujemy właściwy za pomocą dynamicznego tagu import(). Pozwala to zmniejszyć liczbę bajtów, które użytkownicy potrzebują do wzbogacenia witryny o kod.

Komponenty sieciowe

Komponenty sieciowe to elementy niestandardowe, które obejmują funkcje działania dostępne w języku JavaScript i są identyfikowane za pomocą niestandardowych nazw, np. <web-codelab>. Projekt ten dobrze sprawdza się w witrynach w dużej mierze statycznej, takich jak web.dev – przeglądarka zarządza cyklem życia elementów w miarę aktualizowania kodu HTML witryny, prawidłowo informując o dołączeniu elementów do strony lub ich odłączeniu. Przestarzałe przeglądarki po prostu ignorują komponenty sieciowe i renderują to, co pozostały w DOM.

Każdy komponent internetowy jest klasą z metodami takimi jak connectedCallback(), disconnectedCallback() czy attributeChangedCallback(). Elementy niestandardowe web.dev najczęściej dziedziczą z elementu LitElement, który stanowi prostą podstawę dla złożonych komponentów.

Komponenty web.dev używają na wielu stronach komponentów sieciowych, ale nigdzie nie jest to konieczne niż na stronie Measure. Większość funkcji dostępnych na tej stronie udostępniają dwa elementy:

<web-url-chooser-container></web-url-chooser-container>
<web-lighthouse-scores-container></web-lighthouse-scores-container>

Elementy te tworzą kolejne elementy zapewniające większą funkcjonalność. Co ważne, te elementy to tylko część naszego zwykłego kodu źródłowego Markdown, a nasz zespół ds. treści może dodać rozszerzone funkcje do każdej strony, nie tylko do węzła Measure.

Nasze komponenty sieciowe najczęściej korzystają z modelu komponentu kontenera, który jest popularny w React, choć obecnie jest to już nieco przejść do wersji Informatywnej. Każdy element -container łączy się z naszym stanem globalnym (dostarczanym przez unistore), a następnie renderuje element wizualny, który z kolei renderuje rzeczywiste węzły DOM, które mają własny styl lub inne wbudowane funkcje.

Diagram pokazujący związek między stanem globalnym a używającymi go elementami HTML.
Stan globalny i komponent sieciowy

Nasze najbardziej złożone komponenty sieciowe służą do wizualizacji globalnych działań i stanu. Na przykład dzięki web.dev możesz sprawdzić swoją ulubioną witrynę, a potem opuścić stronę Wskaźnik. Jeśli wrócisz, zobaczysz, że zadanie jest nadal wykonywane.

Nasze proste komponenty wzbogacają treści statyczne, a także tworzą świetne wizualizacje (np. każdy wykres liniowy jest własnym elementem <web-sparkline-chart>), który nie ma związku ze stanem globalnym.

Porozmawiajmy

Zespół inżynierów web.dev (Rob, Ewa, Michael i Sam) wkrótce przedstawi bardziej szczegółowe informacje techniczne.

Mamy nadzieję, że te informacje pozwoliły Ci znaleźć pomysły na własne projekty. Jeśli masz pytania lub prośby związane z tematem tego bloga, skontaktuj się z nami na Twitterze.