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

To pierwszy post na blogu inżynierów web.dev. W najbliższych miesiącach chcemy udostępniać przydatne informacje o naszych działaniach. Wypatruj więc posty z tagiem Blog inżynierski. W tym artykule omówimy proces kompilacji witryny statycznej i (opcjonalnie) kod JavaScript naszych komponentów internetowych.

web.dev zawiera treści dotyczące tworzenia nowoczesnych stron internetowych i umożliwia pomiar wydajności witryny. Doświadczeni użytkownicy mogą zauważyć, że nasze narzędzie Measure to tylko interfejs Lighthouse, który jest też dostępny w Narzędziach deweloperskich Chrome. Po zalogowaniu się na stronie web.dev możesz regularnie przeprowadzać audyty Lighthouse w swojej witrynie, aby sprawdzać, jak zmienia się jej wynik w czasie. Wrócę do strony aplikacji Measure nieco później, ponieważ uważam, że jest ona dość wyjątkowa. 🎊

Wprowadzenie

Web.dev to witryna statyczna, która jest generowana na podstawie kolekcji plików Markdown. Używamy Eleventy, ponieważ jest to dopracowane, rozszerzalne narzędzie, które ułatwia przekształcanie Markdowna w HTML.

Używamy też nowoczesnych pakietów JavaScript, które wyświetlamy tylko w przeglądarkach obsługujących type="module", w tym asyncawait. Z przyjemnością korzystamy też z funkcji obsługiwanych przez przeglądarki evergreen, ale nie przez starsze wersje. Ponieważ nasza witryna jest statyczna, do odczytania jej treści nie jest wymagany JavaScript.

Po zakończeniu procesu kompilacji, który obejmuje generowanie statycznego kodu HTML i zbiorcze JavaScripta z Rollupem, web.dev można hostować na prostym serwerze statycznej zawartości na potrzeby testowania. Witryna jest prawie całkowicie statyczna, ale mamy kilka specjalnych potrzeb, które nadal wymagają korzystania z niestandardowego serwera Node.js. Obejmują one przekierowania w przypadku nieprawidłowych domen oraz kod do analizowania preferowanego języka użytkownika w przypadku nadchodzącej funkcji internacjonalizacji.

Generowanie statycznego

Każda strona na web.dev jest napisana w języku Markdown. Wszystkie strony zawierają materiał wstępny, który zawiera metadane dotyczące każdego wpisu. Te metadane są przetwarzane w układzie każdej strony, tworząc 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...

Te informacje wstępne umożliwiają zdefiniowanie dowolnych właściwości, takich jak autorzy, data publikacji i tagi. Eleventy wygodnie udostępnia informacje wstępne jako dane w prawie każdym komponencie, szablonie lub innym kontekście, w którym chcemy wykonać jakąś inteligentną czynność. Obiekt danych zawiera też to, co Eleventy nazywa kaskadą danych – różne dane pobierane z każdej strony, z układu strony i z danych znajdujących się w hierarchicznej strukturze folderów.

Każdy unikalny układ opisuje inny typ treści i może odziedziczyć elementy z innych układów. Na stronie web.dev używamy tej funkcji, aby prawidłowo wyświetlać różne typy treści (np. posty i laboratoria kodu), zachowując jednocześnie jedną najwyższą warstwę układu HTML.

Kolekcje

Eleventy zapewnia programowy sposób tworzenia dowolnych kolekcji treści. Dzięki temu mogliśmy wprowadzić obsługę stron z przewijaniem i generować strony wirtualne (strony, które nie mają odpowiadającego pliku Markdown na dysku) dla autorów postów. Na przykład strony autorów tworzymy za pomocą szablonu zawierającego wyrażenie dla jego adresu bezpośredniego (dzięki czemu szablon jest ponownie renderowany dla każdego autora) oraz zbioru.

W efekcie możesz mieć np. prostą stronę z wszystkimi wpisami Addy.

Ograniczenia

Obecnie nie możemy łatwo podłączyć się do procesu kompilacji Eleventy, ponieważ jest on deklaratywny, a nie imperatywny: opisujesz, czego oczekujesz, a nie jak chcesz to osiągnąć. Trudno jest uruchomić Eleventy jako część większego narzędzia do kompilacji, ponieważ można go wywołać tylko za pomocą interfejsu wiersza poleceń.

Szablony

web.dev używa systemu szablonów Nunjucks, który został pierwotnie opracowany przez firmę Mozilla. Nunjucks zawiera typowe funkcje szablonów, takie jak pętle i warunki, ale pozwala też definiować krótkie kody, które generują dodatkowy kod HTML lub wywołują inne reguły.

Podobnie jak większość zespołów tworzących strony ze statycznymi treściami, zaczęliśmy od podstaw i z czasem dodaliśmy skróty kódów – do tej pory około 20 skrótów. Większość z nich generuje tylko kod HTML (w tym nasze niestandardowe komponenty internetowe). Oto przykład:

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

Wyglądać to będzie tak:

W rzeczywistości tworzy on 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>

Chociaż wykracza to poza zakres tego wpisu, web.dev używa też skrótów jako rodzaju metajęzyka programowania. Shortcode’y przyjmują argumenty, z których jeden to zawartość. Nie jest wymagane, aby skróty zwracały cokolwiek, więc można ich używać do tworzenia stanu lub uruchamiania innych działań. 🤔💭

Tworzenie scenariusza

Jak już wspomnieliśmy, web.dev to witryna statyczna, która 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. Jest to niezwykle ważna część naszego podejścia do udostępniania web.dev wszystkim.

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

  1. kod Bootstrap, który obejmuje kod stanu globalnego, Analytics i przekierowywanie SPA;
  2. kod i CSS do komponentów internetowych, które stopniowo ulepszają witrynę.

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

Określamy też kilka różnych punktów wejścia do naszej witryny na podstawie tego, jaki adres URL został użyty, i wczytujemy odpowiedni adres za pomocą dynamicznego atrybutu import(). Dzięki temu zmniejsza się liczba bajtów, których potrzebują użytkownicy, zanim witryna zostanie ulepszona za pomocą kodu.

Komponenty sieciowe

Składniki internetowe to elementy niestandardowe, które otaczają funkcje czasu wykonywania w JavaScript i są identyfikowane za pomocą niestandardowych nazw, np. <web-codelab>. Ten projekt dobrze sprawdza się w przypadku stron głównie statycznych, takich jak web.dev: przeglądarka zarządza cyklem życia elementu podczas aktualizowania kodu HTML strony, prawidłowo informując o dołączeniu lub odłączeniu elementów od strony. Przeglądarki przestarzałe ignorują komponenty internetowe i renderują tylko to, co pozostało w DOM.

Każdy element internetowy to klasa z metodami, takimi jak connectedCallback(), disconnectedCallback()attributeChangedCallback(). Elementy niestandardowe web.dev w większości dziedziczą po LitElement, który stanowi prostą podstawę dla złożonych komponentów.

Chociaż web.dev używa komponentów internetowych na wielu stronach, są one najbardziej potrzebne na stronie Pomiar. Większość funkcji na tej stronie zapewniają 2 elementy:

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

Te elementy tworzą kolejne elementy, które zapewniają więcej funkcji. Co ważne, te elementy stanowią tylko część naszego zwykłego kodu źródłowego Markdown, a nasz zespół ds. treści może dodawać rozszerzone funkcje do dowolnej strony, a nie tylko do węzła Measure.

Nasze komponenty internetowe najczęściej korzystają z modelu komponentu kontenera, który stał się popularny dzięki Reactowi, choć obecnie jest już nieco przestarzały. Każdy element -container łączy się z naszym stanem globalnym (dostarczanym przez unistore), a potem renderuje element wizualny, który z kolei renderuje rzeczywiste węzły DOM z układem stylów lub inną wbudowaną funkcjonalnością.

Schemat pokazujący związek między stanem globalnym a elementami HTML, które go używają.
Stan globalny i komponent internetowy

Nasze najbardziej złożone komponenty internetowe służą do wizualizacji globalnych działań i stanu. Na przykład web.dev umożliwia przeprowadzenie audytu ulubionej witryny, a następnie przejście z tej strony. Po powrocie zobaczysz, że zadanie jest nadal w toku.

Nasze proste komponenty wzbogacają statyczne treści lub tworzą niesamowite wizualizacje (np. każda wykresy liniowe to osobny <web-sparkline-chart>), które nie mają żadnego związku ze stanem globalnym.

Porozmawiajmy

Zespół inżynierów web.dev (Rob, Ewa, MichaelSam) wkrótce opublikuje więcej szczegółowych informacji technicznych.

Mamy nadzieję, że nasz sposób działania zainspiruje Cię do tworzenia własnych projektów. Jeśli masz pytania lub chcesz zasugerować tematy do omówienia w blogu, skontaktuj się z nami na Twitterze.