プログレッシブウェブアプリを最適化する方法:基本を超えて
公開: 2022-03-10プログレッシブウェブアプリケーション(PWA)は、2020年も引き続き人気を集めています。コンバージョン率の向上、カスタマーエンゲージメント、ページの読み込み速度の低下、開発とオーバーヘッドのコストの削減のメリットを考えると、驚くことではありません。
Twitter、Uber、Tinder、Pinterest、Forbesなどの尊敬されている企業もPWAで成功を収めていることがわかります。 そして、それらはすべて、プログレッシブアプリを実装することによる大きなメリットを誇っています。
幸いなことに、PWAの開発は、大予算の企業だけが手に入れることができるものではありません。 これらのアプリケーションは、中小企業と平均的な企業に等しくサービスを提供し、作成はそれほど複雑ではありません。
PWAのコアの構築に焦点を当てた、SmashingMagazineのプログレッシブWebアプリの包括的な初心者向けガイドを見つけることができます。
ただし、さらに一歩進んで、オフライン機能、ネットワークベースの最適化、クロスデバイスユーザーエクスペリエンス、SEO機能、邪魔にならない通知やリクエストなど、PWAに最新の品質を導入する方法を学びましょう。 これらのヒントをPWAに実装できるように、サンプルコードまたはより具体的なガイドへの参照もあります。
プログレッシブWebアプリケーション(PWA)の概要
基本をスキップせずに、PWAの核心をすばやく確認しましょう。
PWAとは何ですか?
「プログレッシブウェブアプリ(PWA)は、最新のAPIで構築および拡張されており、単一のコードベースで、あらゆるデバイスの誰にでも、どこにでも到達できるように、拡張された機能、信頼性、およびインストール可能性を提供します。」
—Googleの開発者
つまり、PWAは、ユーザーがスタンドアロンアプリケーションとして使用できるWebサイトです。 PWAはインストールを必要とせず、さまざまなデバイスで使用できるという点で、ネイティブアプリとは異なります。ネイティブアプリは、主にモバイルデバイス用に構築されています。
PWAはどのように機能しますか?
PWAのコアは、Webアプリマニフェスト、サービスワーカー、およびアプリケーションシェルの3つのコンポーネントで構成されています。 それらを構築するための詳細な手順は、上記のビギナーズガイドにあります。
これらのコンポーネントの機能は次のとおりです。
Webアプリマニフェスト
Webアプリマニフェストは、Webサイトをフルスクリーンモードでスタンドアロンアプリケーションとして実行するためのコアです。 PWAの外観を定義し、さまざまなデバイスに合わせて最適化し、アプリケーションのインストール後に表示されるアイコンを割り当てることができます。
サービスワーカー
サービスワーカーは、キャッシュされたデータをフェッチするか、インターネット接続がないことをユーザーに通知することにより、PWAのオフライン使用を可能にします。 サーバー接続が復元されると、ServiceWorkerは最新のデータも取得します。
アプリケーションシェルアーキテクチャ
アプリケーションシェルは、ユーザーがPWAにアクセスしたときに表示されるものです。 これは、ユーザーインターフェイスを強化するために必要な最小限のHTML、CSS、およびJavaScriptです。 PWAを開発するときは、アプリケーションシェルのリソースとアセットをブラウザーにキャッシュできます。
PWAへの最新の特性の展開
コア機能に加えて、最新のPWAは、ユーザーをより優れたユーザーエクスペリエンスに向けてさらに駆り立てる追加の特性を採用しています。
PWAのいくつかの特定の最新の特性を見て、これらをPWAに追加する方法を学びましょう。 次の品質は、Google開発者による基本的なPWAへの優れた追加と見なされます。
アプリケーションはオンラインと同じようにオフラインで動作します
PWAを構築するときに、コアの一部としてカスタムオフラインページを開発することもできます。 ただし、インターネットに接続していなくても、接続が必要になる特定の時点まで、PWAが機能し続けると、はるかにユーザーフレンドリーになります。 そうでなければ、ユーザーエクスペリエンスは、PWAの問題点についての彼女の記事で説明しているように、ケーキを注文するというAnkitaMasandの試練と同じくらいイライラする可能性があります。
キャッシュされたコンテンツ、バックグラウンド同期、およびスケルトン画面を使用することで、より重要なユーザーエクスペリエンスを実現できます。 それぞれを見てみましょう。
IndexedDB
でキャッシュされたコンテンツ
IndexedDB
は、ブラウザ内のNoSQLストレージシステムであり、PWAをオフラインで動作させるために必要なデータをキャッシュおよび取得するために使用できます。
ただし、すべてのブラウザがIndexedDB
をサポートしているわけではないため、最初に行うことは、ユーザーのブラウザがIndexedDBをサポートしているかどうかを確認することです。
if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; }
この後、IndexedDBAPIを使用してキャッシュされたコンテンツを作成できます。 これは、データベースを開き、オブジェクトストアを追加し、このストアにアイテムを追加するGoogle開発者の例です。
var db; var openRequest = indexedDB.open('test_db', 1); openRequest.onupgradeneeded = function(e) { var db = e.target.result; console.log('running onupgradeneeded'); if (!db.objectStoreNames.contains('store')) { var storeOS = db.createObjectStore('store', {keyPath: 'name'}); } }; openRequest.onsuccess = function(e) { console.log('running onsuccess'); db = e.target.result; addItem(); }; openRequest.onerror = function(e) { console.log('onerror!'); console.dir(e); }; function addItem() { var transaction = db.transaction(['store'], 'readwrite'); var store = transaction.objectStore('store'); var item = { name: 'banana', price: '$2.99', description: 'It is a purple banana!', created: new Date().getTime() }; var request = store.add(item); request.onerror = function(e) { console.log('Error', e.target.error.name); }; request.onsuccess = function(e) { console.log('Woot! Did it'); }; }
バックグラウンド同期
PWAがバックグラウンドでデータを同期する場合、ユーザーはオフライン中にアクションを実行できます。アクションは、インターネット接続が復元されたときに実行されます。 簡単な例はメッセージングアプリです。 ユーザーは、オフラインのときにメッセージが送信されるまで待つことなくメッセージを送信できます。接続が復元されると、バックグラウンド同期によってメッセージが自動的に送信されます。
JakeArchibaldによるバックグラウンド同期機能を開発する方法の例を次に示します。
// Register your service worker: navigator.serviceWorker.register('/sw.js'); // Then later, request a one-off sync: navigator.serviceWorker.ready.then(function(swRegistration) { return swRegistration.sync.register('myFirstSync'); });
次に、 /sw.js
でイベントをリッスンします。
self.addEventListener('sync', function(event) { if (event.tag == 'myFirstSync') { event.waitUntil(doSomeStuff()); } });
スケルトンスクリーン
スケルトン画面を使用する主な利点の1つは、ユーザーがアイドル状態ではなく、アプリケーションが機能していると感じることです。 ユーザーが接続を持っていない間、スケルトン画面はコンテンツなしでインターフェースを引き出します—接続が回復すると、コンテンツは塗りつぶされます。
Code My UIには、PWAのスケルトン画面を作成するために使用できる優れたコードスニペットがいくつかあります。

ネットワーク使用量に基づく最適化
PWAの主な利点は、ユーザーにより高速なエクスペリエンスを提供することです。 PWAにキャッシュファーストネットワークを使用させ、リソースに優先順位を付け、ネットワーク品質に基づいて適応型ロードを使用することにより、ロード速度をさらに最適化できます。
これらをPWAに開発する方法を見てみましょう。
最初にキャッシュし、次にネットワーク
キャッシュされたコンテンツを最初に使用すると、PWAがオフラインで機能できるようになり、ネットワークカバレッジの低いエリアでもユーザーがコンテンツにアクセスできるようになります。 これを行うには、コンテンツをキャッシュするService Workerを作成し、それをフェッチします。
これは、サービスワーカーを使用した静的HTMLのキャッシュに関するJeffPosnickの例です。
self.addEventListener('fetch', event => { if (event.request.mode === 'navigate') { // See /web/fundamentals/getting-started/primers/async-functions // for an async/await primer. event.respondWith(async function() { // Optional: Normalize the incoming URL by removing query parameters. // Instead of https://example.com/page?key=value, // use https://example.com/page when reading and writing to the cache. // For static HTML documents, it's unlikely your query parameters will // affect the HTML returned. But if you do use query parameters that // uniquely determine your HTML, modify this code to retain them. const normalizedUrl = new URL(event.request.url); normalizedUrl.search = ''; // Create promises for both the network response, // and a copy of the response that can be used in the cache. const fetchResponseP = fetch(normalizedUrl); const fetchResponseCloneP = fetchResponseP.then(r => r.clone()); // event.waitUntil() ensures that the service worker is kept alive // long enough to complete the cache update. event.waitUntil(async function() { const cache = await caches.open('my-cache-name'); await cache.put(normalizedUrl, await fetchResponseCloneP); }()); // Prefer the cached response, falling back to the fetch response. return (await caches.match(normalizedUrl)) || fetchResponseP; }()); } });
リソースの優先順位付け
デフォルトでは、PWAはその軽快な性質により、同様のネイティブアプリよりも優れたパフォーマンスを発揮します。 さらに、PWAはブラウザのキャッシュを使用するため、どのリソースが優先され、使用される前でもレンダリングする必要があるかを示すことができます。 動的コンテンツはフェッチする前に更新する必要があるため、これは主に静的要素で機能します。
HTMLの<link>
文字列を使用して、要素の優先度を指定できます。 rel=”preconnect”
およびrel=”dns-prefetch.”
Maximiliano Firtmanは、ブラウザのエンジン内でWebフォントに優先順位を付けることにより、この簡単な例を示しています。
<link rel=”preload” as=”font” href=”font.woff” crossorigin>
アダプティブローディングの実装
WiFiと4Gのインターネット速度はどこからでもアクセスできるわけではなく、ユーザーは2Gと3G接続でインターネットにアクセスできます。 できるだけ多くの人がPWAにアクセスできるようにしたいので、インターネットの低速でも実行できるようにPWAを最適化することをお勧めします。

これは、ユーザーの接続タイプに基づいてPWA要素をロードするアダプティブロードを実装することで実現できます。

最も簡単な方法は、キャッシュ戦略用の多数の既製のプラグインを含むGoogleのワークボックスツールを使用することです。
カスタムキャッシュ戦略を定義するとします。 DemianRenzulliとJeffPosnickの例としてこれを行う方法は次のとおりです。
const adaptiveLoadingPlugin = { requestWillFetch: async ({request}) => { const urlParts = request.url.split('/'); let imageQuality; switch ( navigator && navigator.connection ? navigator.connection.effectiveType : '' ) { //... case '3g': imageQuality = 'q_30'; break; //... } const newUrl = urlParts .splice(urlParts.length - 1, 0, imageQuality) .join('/') .replace('.jpg', '.png'); const newRequest = new Request(newUrl.href, {headers: request.headers}); return newRequest; }, };
次に、プラグインを、画像のURL( /img/
など)に一致する正規表現を含むcacheFirst
ストラテジーに渡します。
workbox.routing.registerRoute( new RegExp('/img/'), workbox.strategies.cacheFirst({ cacheName: 'images', plugins: [ adaptiveLoadingPlugin, workbox.expiration.Plugin({ maxEntries: 50, purgeOnQuotaError: true, }), ], }), );
すべてのプラットフォームで優れたユーザーエクスペリエンス
優れたPWAは、ブラウザ、モバイル、タブレットでシームレスに機能します。 Androidデバイスを使用することがインターネットにアクセスする最も一般的な方法(38.9%の市場シェア)ですが、すべてのプラットフォーム向けにアプリケーションを最適化することは、PWAのコア機能の開発の一部です。
PWAが読み込まれるときのジャンプを減らし、PWAが任意の入力方法で機能することを確認するなど、使いやすさを向上させ、優れたユーザーエクスペリエンスを提供するためのさらなる手順を実行できます。
これらの各側面にアプローチする方法は次のとおりです。
「ジャンピー」なコンテンツの読み込みを減らす
高速インターネットでも、サイトの要素が順番に読み込まれるため、読み込み中にサイトのコンテンツがシフトする可能性があります。 この影響は、接続速度が遅いとさらに悪化し、ユーザーエクスペリエンスに大きな悪影響を及ぼします。
ロード中にコンテンツがシフトする最も一般的な要素は画像です。これらは一般に大きく、コンテンツをロードする際の優先順位ではないためです。 HTML構造のレンダリング後に優先順位を付けることができる小さなプレースホルダー画像を使用することで、「遅延読み込み」でこの問題に取り組むことができます。
JavaScriptで実際の画像の前に最初に読み込まれる軽量画像を追加する方法に関するMozillaの開発者による例を次に示します。
<img src='data/img/placeholder.png' data-src='data/img/SLUG.jpg' alt='NAME'>
app.js
ファイルは、次のようにdata-src属性を処理します。
let imagesToLoad = document.querySelectorAll('img[data-src]'); const loadImages = (image) => { image.setAttribute('src', image.getAttribute('data-src')); image.onload = () => { image.removeAttribute('data-src'); }; };
そして、ループを作成します。
imagesToLoad.forEach((img) => { loadImages(img); });
また、他の要素とのコンテンツのジャンプを減らすことについて、SmashingMagazineの完全なガイドを確認することもできます。
PWAは任意の入力方式で機能します
PWAがさまざまなデバイスでどのように機能するかについて説明しました。 さらに一歩進めるには、タッチ、マウス、スタイラスなど、ユーザーがこれらのデバイスで使用できる他の入力方法も考慮する必要があります。
Pointer Events APIをPWAに追加すると、主にこの問題が解決されます。 Googleの開発者によると、これにアプローチする方法は次のとおりです。
まず、ブラウザがポインタイベントをサポートしているかどうかを確認します。
if (window.PointerEvent) { // Yay, we can use pointer events! } else { // Back to mouse and touch events, I guess. }
次に、さまざまな入力メソッドが実行できるアクションを定義できます。
switch(ev.pointerType) { case 'mouse': // Do nothing. break; case 'touch': // Allow drag gesture. break; case 'pen': // Also allow drag gesture. break; default: // Getting an empty string means the browser doesn't know // what device type it is. Let's assume mouse and do nothing. break; }
ほとんどのブラウザにはすでにタッチ対応機能があるため、他に何も追加する必要はありません。
検索で発見可能
ネイティブアプリケーションに対するPWAの主な利点の1つは、PWAが本質的にWebサイトであり、検索エンジンがそれらにインデックスを付けることができることです。 これにより、SEO戦略を展開して、PWAコンテンツをより見つけやすくすることができます。
まず、PWAの各URLに、SEO最適化アクティビティのベースラインである一意の説明的なタイトルとメタ説明が含まれていることを確認します。
PWAを検索可能にするために実行できる他のいくつかの手順を見てみましょう。
PWAのファインダビリティを分析する
Googleの検索コンソールには、サイト(PWA)を分析して結果を報告する優れたツールがあります。 これを使用して、サイトの基本的なスキャンを実行し、修正を開始できる弱点を見つけることができます。
または、ChromeブラウザでLighthouseを使用して、SEO監査を実行することもできます。
まず、ターゲットURLに移動します。 次に、 Control+Shift+J
(Macの場合はCommand+Option+J
)を押して、開発者のツールメニューを開きます。 [灯台]タブを選択し、[SEOカテゴリ]ボックスにチェックマークを付けて、レポートを生成します。

構造化データを使用する
Googleの検索エンジンは、構造化データを使用して、ウェブページ上のコンテンツの目的を理解します。
構造化データは、ページに関する情報を提供し、ページのコンテンツを分類するための標準化された形式です。 たとえば、レシピページでは、材料、調理時間と温度、カロリーなどは何ですか。
- グーグル
コーディングを開始する前に、Googleは一般的な構造化データエラーの便利なリストとそれらを修正するための関連ガイドラインもまとめました。 この資料を研究することで、避けるべきことの良いベースラインが得られるはずです。
Frederick O'Brienは、Smashing Magazine、構造化データを設計プロセスに組み込むに関する優れたガイドを作成しました。このガイドでは、構造化データを最初から構築する方法について説明しています。
ユーザーフレンドリーな通知と許可リクエスト
大事なことを言い忘れましたが、通知と許可リクエストを最適化することでユーザーエクスペリエンスを向上させることができます。これにより、混乱や煩わしさだけでなく、ユーザーにサービスを提供できます。
一般的に常識に頼ることができますが、邪魔にならないプッシュ通知を作成したり、ユーザーにメッセージの購読を解除するオプションを提供したりするなど、実装できる実用的なヒントもあります。
通信のための微妙な許可要求
Webサイトとユーザー間の通信を自動化するには、チャットボットと通知の2つの最新の方法があります。
PWAのコンテキストでは、チャットボットの主な利点は、ユーザーと対話するためにユーザーの許可を必要としないことです。 ただし、使用するチャットボットアプリケーションによっては、ユーザーが微妙なメッセージを見逃す可能性があります。 一方、通知にはユーザーの許可が必要ですが、はるかに目立ちます。
チャットボットを別のサードパーティアプリケーションとして追加できるため、ユーザーフレンドリーなプッシュ通知の作成に焦点を当てましょう。 そもそもプッシュ通知を作成する方法についてのガイドが必要な場合は、IndrekLasnによるすばらしいガイドをご覧ください。
邪魔にならない許可リクエストを作成する最も簡単な方法は、doubleリクエストを使用することです。 これは、ユーザーのOSからのデフォルトのインタラクションに加えて、サイトへのカスタムインタラクションを含めることを意味します。
Matt Gauntは、次の画像を使用して、この効果の完璧なイラストを提供しています。
コンテキストを提供しないデフォルトの通知許可リクエストは次のとおりです。

上記のデフォルトの通知権限の前に追加されたカスタムインタラクションは次のとおりです。

OSのデフォルトアラートの前にカスタムアラートを追加することで、ユーザーに通知の目的をより明確に説明できます。 これにより、ユーザーがサイトの通知をオプトインする可能性が高くなります。
ユーザーが通知をオプトアウトできるようにする
ユーザーにとって、サイトのプッシュ通知を無効にすることは、使用しているデバイスに関係なく非常に面倒です。 したがって、メッセージをオプトアウトするオプションをユーザーに提供することは、ユーザーエクスペリエンスの点で大いに役立ちます。
コードとUIにサブスクライブ解除関数を実装する方法に関するMattGauntの例を次に示します。
まず、 pushButton
のクリックリスナーを定義します。
pushButton.addEventListener('click', function() { pushButton.disabled = true; if (isSubscribed) { unsubscribeUser(); } else { subscribeUser(); } });
次に、新しい関数を追加します。
function unsubscribeUser() { swRegistration.pushManager.getSubscription() .then(function(subscription) { if (subscription) { // TODO: Tell application server to delete subscription return subscription.unsubscribe(); } }) .catch(function(error) { console.log('Error unsubscribing', error); }) .then(function() { updateSubscriptionOnServer(null); console.log('User is unsubscribed.'); isSubscribed = false; updateBtn(); }); }
ユーザーが選択した場合に通知を無効にするサブスクライブボタンを正常に実装した後のコンソールでの外観は次のとおりです。

Console.log
の例。 (大プレビュー)結論
PWAは、サイトのトラフィックを増やし、ユーザーエクスペリエンスを拡大するために非常に強力です。 PWAをさらに最適化するために、この記事で説明されているこれらの最新のソリューションを使用して、パフォーマンスと機能を強化できます。
また、すべてを一度に実装する必要はありません。 これらの提案はそれぞれPWAを促進するのに役立つため、最も関連性の高いオプションを自由に選択してください。
その他のリソース
- Googleによるプログレッシブウェブアプリのトレーニング
- web.devによるプログレッシブウェブアプリ
- Mozillaによるプログレッシブウェブアプリ(PWA)