Te ćwiczenia z programowania są częścią kursu szkoleniowego „Tworzenie progresywnych aplikacji internetowych”, który został opracowany przez zespół Google Developers Training. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności.
Szczegółowe informacje o szkoleniu znajdziesz w omówieniu tworzenia progresywnych aplikacji internetowych.
Wprowadzenie
W tym module użyjesz Lighthouse do sprawdzenia, czy witryna spełnia standardy progresywnej aplikacji internetowej (PWA). Dodasz też funkcje offline za pomocą interfejsu Service Worker API.
Czego się nauczysz
- Jak przeprowadzać audyty witryn za pomocą Lighthouse
- Jak dodać do aplikacji funkcje offline
Co warto wiedzieć
- Podstawy HTML, CSS i JavaScript
- znajomość obietnic ES2015;
Wymagania
- Komputer z dostępem do terminala lub powłoki
- Połączenie z internetem
- przeglądarka Chrome (do korzystania z Lighthouse);
- edytor tekstu,
- Opcjonalnie: Chrome na urządzeniu z Androidem
Pobierz lub sklonuj repozytorium pwa-training-labs z GitHub i w razie potrzeby zainstaluj wersję LTS Node.js.
Przejdź do katalogu offline-quickstart-lab/app/ i uruchom lokalny serwer programistyczny:
cd offline-quickstart-lab/app npm install node server.js
W dowolnej chwili możesz zamknąć serwer, klikając Ctrl-c.
Otwórz przeglądarkę i wejdź na stronę localhost:8081/. Powinna wyświetlić się prosta, statyczna strona internetowa.
Uwaga: wyrejestruj wszystkie skrypty service worker i wyczyść wszystkie ich pamięci podręczne na potrzeby hosta lokalnego, aby nie zakłócały działania modułu. W Narzędziach deweloperskich w Chrome możesz to zrobić, klikając Wyczyść dane witryny w sekcji Wyczyść pamięć na karcie Aplikacja.
Otwórz folder offline-quickstart-lab/app/ w preferowanym edytorze tekstu. W folderze app/ będziesz tworzyć laboratorium.
Ten folder zawiera:
- Folder
images/zawiera przykładowe obrazy. styles/main.cssto główny arkusz stylówindex.htmlto główna strona HTML naszej przykładowej witryny.package-lock.jsonipackage.jsonśledzą zależności aplikacji (w tym przypadku jedynymi zależnościami są zależności serwera lokalnego).server.jsto lokalny serwer programistyczny do testowania.service-worker.jsto plik service worker (obecnie pusty).
Zanim zaczniemy wprowadzać zmiany w witrynie, przeprowadźmy audyt za pomocą narzędzia Lighthouse, aby sprawdzić, co można poprawić.
Wróć do aplikacji (w Chrome) i otwórz kartę Audyty w Narzędziach dla programistów. Powinna pojawić się ikona Lighthouse i opcje konfiguracji. Wybierz „Urządzenia mobilne” w sekcji Urządzenie, zaznacz wszystkie Audyty, wybierz jedną z opcji Ograniczanie i kliknij Wyczyść pamięć:

Kliknij Uruchom audyty. Sprawdzanie trwa kilka minut.
Wyjaśnienie
Po zakończeniu audytu w Narzędziach deweloperskich powinien pojawić się raport z wynikami. Powinny się wyświetlić wyniki, np. takie (wyniki mogą się różnić):
Uwaga: wyniki Lighthouse są przybliżone i mogą zależeć od środowiska (np. jeśli masz otwartych wiele okien przeglądarki). Twoje wyniki mogą się różnić od tych, które widzisz tutaj.

Sekcja Progresywna aplikacja internetowa powinna wyglądać podobnie do tej:

Raport zawiera wyniki i dane w 5 kategoriach:
- Progresywna aplikacja internetowa
- Wyniki
- Ułatwienia dostępu
- Sprawdzone metody
- SEO
Jak widać, nasza aplikacja ma niską ocenę w kategorii progresywnych aplikacji internetowych (PWA). Poprawmy nasz wynik!
Poświęć chwilę na przejrzenie sekcji raportu dotyczącej PWA i sprawdź, czego brakuje.
Rejestrowanie skryptu service worker
Jednym z błędów wymienionych w raporcie jest brak zarejestrowanego procesu service worker. Obecnie w lokalizacji app/service-worker.js znajduje się pusty plik service worker.
Dodaj ten skrypt na końcu pliku index.html, tuż przed tagiem zamykającym </body>:
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('service-worker.js')
.then(reg => {
console.log('Service worker registered! 😎', reg);
})
.catch(err => {
console.log('😥 Service worker registration failed: ', err);
});
});
}
</script>Wyjaśnienie
Ten kod rejestruje pusty plik skryptu service worker service-worker.js po wczytaniu strony. Obecny plik skryptu service worker jest jednak pusty i nie będzie wykonywać żadnych działań. W następnym kroku dodamy kod usługi.
Wczytywanie wstępne zasobów do pamięci podręcznej
Kolejny błąd wymieniony w raporcie to brak odpowiedzi aplikacji z kodem stanu 200, gdy jest ona offline. Aby to rozwiązać, musimy zaktualizować proces roboczy usługi.
Dodaj ten kod do pliku z usługą Service Worker (service-worker.js):
const cacheName = 'cache-v1';
const precacheResources = [
'/',
'index.html',
'styles/main.css',
'images/space1.jpg',
'images/space2.jpg',
'images/space3.jpg'
];
self.addEventListener('install', event => {
console.log('Service worker install event!');
event.waitUntil(
caches.open(cacheName)
.then(cache => {
return cache.addAll(precacheResources);
})
);
});
self.addEventListener('activate', event => {
console.log('Service worker activate event!');
});
self.addEventListener('fetch', event => {
console.log('Fetch intercepted for:', event.request.url);
event.respondWith(caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request);
})
);
});Teraz wróć do przeglądarki i odśwież stronę. Sprawdź w konsoli, czy service worker:
- zarejestrowano
- zainstalowana
- Aktywowano
Uwaga: jeśli skrypt service worker został już wcześniej zarejestrowany lub masz problem z wywołaniem wszystkich zdarzeń, wyrejestruj wszystkie skrypty service worker i odśwież stronę. Jeśli to nie pomoże, zamknij wszystkie wystąpienia aplikacji i uruchom ją ponownie.
Następnie zamknij lokalny serwer programistyczny w wierszu poleceń, uruchamiając polecenie Ctrl + c. Ponownie odśwież stronę i zobacz, że wczytuje się ona nawet wtedy, gdy serwer jest offline.
Uwaga: w konsoli może pojawić się błąd wskazujący, że nie udało się pobrać komponentu service worker: An unknown error occurred when fetching the script. service-worker.js Failed to load resource: net::ERR_CONNECTION_REFUSED. Ten błąd jest wyświetlany, ponieważ przeglądarka nie może pobrać skryptu service workera (witryna jest offline), ale jest to oczekiwane, ponieważ nie możemy używać service workera do buforowania samego siebie. W przeciwnym razie przeglądarka użytkownika byłaby na zawsze powiązana z tym samym procesem Service Worker.
Wyjaśnienie
Gdy skrypt rejestracji w index.html zarejestruje skrypt service worker, nastąpi zdarzenie install skryptu service worker. Podczas tego zdarzenia install detektor zdarzeń otwiera nazwaną pamięć podręczną i buforuje pliki określone za pomocą metody cache.addAll. Nazywa się to „wstępnym buforowaniem”, ponieważ odbywa się podczas zdarzenia install, które zwykle występuje, gdy użytkownik po raz pierwszy odwiedza Twoją witrynę.
Po zainstalowaniu skryptu service worker i jeśli strona nie jest obecnie kontrolowana przez inny skrypt service worker, nowy skrypt service worker jest „aktywowany” (w skrypcie service worker wywoływany jest detektor zdarzeń activate) i zaczyna kontrolować stronę.
Gdy strona kontrolowana przez aktywowany service worker wysyła żądania dotyczące zasobów, żądania te przechodzą przez service worker, tak jak przez serwer proxy sieci. W przypadku każdego żądania wywoływane jest zdarzenie fetch. W naszym service workerze detektor zdarzeń fetch przeszukuje pamięć podręczną i odpowiada za pomocą zasobu z pamięci podręcznej, jeśli jest on dostępny. Jeśli zasób nie jest w pamięci podręcznej, żądanie jest wysyłane w normalny sposób.
Buforowanie zasobów umożliwia aplikacji działanie offline, ponieważ nie musi ona wysyłać żądań sieciowych. Teraz nasza aplikacja może wyświetlać kod stanu 200, gdy jest offline.
Uwaga: w tym przykładzie zdarzenie aktywacji służy tylko do logowania. Zdarzenie zostało uwzględnione, aby ułatwić debugowanie problemów z cyklem życia service workera.
Opcjonalnie: możesz też wyświetlić zasoby w pamięci podręcznej na karcie Aplikacja w Narzędziach dla deweloperów, rozwijając sekcję Pamięć podręczna:

Uruchom ponownie serwer programistyczny za pomocą polecenia node server.js i odśwież witrynę. Następnie ponownie otwórz kartę Audyty w Narzędziach deweloperskich i ponownie uruchom audyt Lighthouse, klikając Nowy audyt (znak plusa w lewym górnym rogu). Po zakończeniu audytu zobaczysz, że wynik naszej progresywnej aplikacji internetowej jest znacznie lepszy, ale nadal można go poprawić. W następnej sekcji będziemy go dalej ulepszać.
Uwaga: ta sekcja jest opcjonalna, ponieważ testowanie banera instalacji aplikacji internetowej wykracza poza zakres tego modułu. Możesz to sprawdzić samodzielnie, korzystając z zdalnego debugowania.
Nasz wynik PWA nadal nie jest zadowalający. Niektóre z pozostałych błędów wymienionych w raporcie to brak prośby o zainstalowanie naszej aplikacji internetowej oraz brak skonfigurowanego ekranu powitalnego lub kolorów marki na pasku adresu. Możemy rozwiązać te problemy i stopniowo wdrażać funkcję Dodaj do ekranu głównego, spełniając dodatkowe kryteria. Najważniejsze jest utworzenie pliku manifestu.
Tworzenie pliku manifestu
Utwórz w katalogu app/ plik o nazwie manifest.json i dodaj ten kod:
{
"name": "Space Missions",
"short_name": "Space Missions",
"lang": "en-US",
"start_url": "/index.html",
"display": "standalone",
"theme_color": "#FF9800",
"background_color": "#FF9800",
"icons": [
{
"src": "images/touch/icon-128x128.png",
"sizes": "128x128"
},
{
"src": "images/touch/icon-192x192.png",
"sizes": "192x192"
},
{
"src": "images/touch/icon-256x256.png",
"sizes": "256x256"
},
{
"src": "images/touch/icon-384x384.png",
"sizes": "384x384"
},
{
"src": "images/touch/icon-512x512.png",
"sizes": "512x512"
}
]
}Obrazy, do których odwołuje się plik manifestu, są już dostępne w aplikacji.
Następnie dodaj ten kod HTML na końcu tagu <head> w pliku index.html:
<link rel="manifest" href="manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Space Missions">
<meta name="apple-mobile-web-app-title" content="Space Missions">
<meta name="theme-color" content="#FF9800">
<meta name="msapplication-navbutton-color" content="#FF9800">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/index.html">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="apple-touch-icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="icon" sizes="192x192" href="icon-192x192.png">
<link rel="apple-touch-icon" sizes="192x192" href="/images/touch/icon-192x192.png">
<link rel="icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="apple-touch-icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="apple-touch-icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="icon" sizes="512x512" href="/images/touch/icon-512x512.png">
<link rel="apple-touch-icon" sizes="512x512" href="/images/touch/icon-512x512.png">Wróć do witryny. Na karcie Aplikacja w Narzędziach dla programistów wybierz sekcję Wyczyść pamięć i kliknij Wyczyść dane witryny. Następnie odśwież stronę. Teraz wybierz sekcję Manifest. Powinny być widoczne ikony i opcje konfiguracji skonfigurowane w pliku manifest.json. Jeśli nie widzisz zmian, otwórz witrynę w oknie incognito i sprawdź ponownie.
Wyjaśnienie
Plik manifest.json informuje przeglądarkę, jak stylizować i formatować niektóre progresywne aspekty aplikacji, takie jak interfejs przeglądarki, ikona ekranu głównego i ekran powitalny. Możesz też skonfigurować aplikację internetową tak, aby otwierała się w trybie standalone, tak jak aplikacja natywna (czyli poza przeglądarką).
W momencie pisania tego artykułu obsługa niektórych przeglądarek jest nadal w trakcie opracowywania, a tagi <meta> konfigurują podzbiór tych funkcji w przypadku niektórych przeglądarek, które nie mają jeszcze pełnej obsługi.
Aby usunąć starą wersję index.html z pamięci podręcznej (ponieważ nie zawierała ona linku do pliku manifestu), musieliśmy wyczyścić dane witryny. Uruchom kolejny audyt Lighthouse i sprawdź, o ile wzrosła ocena PWA.
Aktywowanie prośby o instalację
Kolejnym krokiem instalacji naszej aplikacji jest wyświetlenie użytkownikom prośby o jej zainstalowanie. Chrome w wersji 67 automatycznie wyświetlał użytkownikom prośbę o instalację, ale od wersji 68 prośba o instalację powinna być aktywowana programowo w odpowiedzi na działanie użytkownika.
Dodaj przycisk „Zainstaluj aplikację” i baner u góry strony index.html (zaraz po tagu <main>) za pomocą tego kodu:
<section id="installBanner" class="banner">
<button id="installBtn">Install app</button>
</section>Następnie nadaj banerowi styl, dodając te style do elementu styles/main.css:
.banner {
align-content: center;
display: none;
justify-content: center;
width: 100%;
}Zapisz plik. Na koniec dodaj do pliku index.html ten tag skryptu:
<script>
let deferredPrompt;
window.addEventListener('beforeinstallprompt', event => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
event.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = event;
// Attach the install prompt to a user gesture
document.querySelector('#installBtn').addEventListener('click', event => {
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice
.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
deferredPrompt = null;
});
});
// Update UI notify the user they can add to home screen
document.querySelector('#installBanner').style.display = 'flex';
});
</script>Zapisz plik. Otwórz aplikację w Chrome na urządzeniu z Androidem, korzystając z zdalnego debugowania. Po wczytaniu strony powinien pojawić się przycisk „Zainstaluj aplikację” (nie będzie on widoczny na komputerze, więc upewnij się, że testujesz na urządzeniu mobilnym). Kliknij przycisk. Powinien pojawić się monit Dodaj do ekranu głównego. Postępuj zgodnie z instrukcjami, aby zainstalować aplikację na urządzeniu. Po zainstalowaniu aplikacji internetowej możesz ją otworzyć w trybie samodzielnym (poza przeglądarką), klikając nowo utworzoną ikonę na ekranie głównym.
Wyjaśnienie
Kod HTML i CSS dodaje ukryty baner i przycisk, których możemy użyć, aby umożliwić użytkownikom aktywowanie prośby o instalację.
Gdy zostanie wywołane zdarzenie beforeinstallprompt, zapobiegamy domyślnemu działaniu (w przypadku którego Chrome 67 i starsze wersje automatycznie wyświetlają użytkownikom prośbę o instalację) i przechwytujemy zdarzenie beforeinstallevent w globalnej zmiennej deferredPrompt. Przycisk „Zainstaluj aplikację” jest następnie konfigurowany tak, aby wyświetlać prompt z metodą beforeinstalleventprompt(). Gdy użytkownik dokona wyboru (zainstaluje lub nie), obietnica userChoice zostanie spełniona zgodnie z jego decyzją (outcome). Na koniec, gdy wszystko będzie gotowe, wyświetlimy przycisk instalacji.
Wiesz już, jak sprawdzać witryny za pomocą Lighthouse i wdrażać podstawowe funkcje offline. Jeśli udało Ci się przejść opcjonalne sekcje, wiesz już też, jak instalować aplikacje internetowe na ekranie głównym.
Więcej zasobów
Lighthouse to oprogramowanie typu open source. Możesz go sklonować, dodać własne testy i zgłaszać błędy. Lighthouse jest też dostępny jako narzędzie wiersza poleceń do integracji z procesami kompilacji.
Aby zobaczyć wszystkie codelaby w ramach szkolenia PWA, zapoznaj się z codelabem wprowadzającym.