WebサイトをPWA(プログレッシブウェブアプリ)にする手順とその必要性
Post on:2019年10月23日
ここ数年、PWA(プログレッシブウェブアプリ)が非常に注目されています。通常のWebページとスマホアプリそれぞれの利点を兼ね備えており、導入したサイトではコンバージョンやユーザーエクスペリエンスの改善が大きく見込めます。
WebサイトをPWAにする手順とその必要性を紹介します。
Turn Your Website into a PWA
by Luca Spezzano
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- PWA(プログレッシブウェブアプリ)とは
- なぜPWAを構築する必要があるのですか?
- すでにPWAを採用しているのはどこですか?
- PWAを作成する時に必要なもの
- Web App Manifest
- Service Worker
- PWAを5分で構築しよう
- 静的キャッシュ
- 動的キャッシュ
- 静的と動的のどちらを使用すべきですか?
PWA(プログレッシブウェブアプリ)とは
プログレッシブウェブアプリ(Progressive Web Apps)とは、Googleも推奨する通常のWebページとモバイルアプリのハイブリッドです。PWAは最新のブラウザが提供する機能とスマホのエクスペリエンスの利点を兼ね備えており、HTML, CSS, JavaScriptなどの標準的なWebテクノロジーで構築されています。
機能としては、オフライン作業、プッシュ通知、デバイスのハードウェアアクセスなど、ネイティブアプリと同等のユーザーエクスペリエンスを可能にします。スマホアプリとまったく同じように、スマホのホームに追加することもできます。
なぜPWAを構築する必要があるのですか?
数週間前に私がPWAに関する詳細情報を探した時に、pwastats.comというとても素敵なサイトを見つけました。このサイトにはPWAを利用している有名企業のデータがあり、どのようにしてサイトのパフォーマンスを改善したのかがよく分かります。
プログレッシブウェブアプリを使用すると、ロード時間を短縮され、ユーザーがオフラインでナビゲートできるようにし、サイトで費やす時間を増やしたり、収益を増やしたり、スマホアプリよりもはるかに多くのことができます。
すでにPWAを採用しているのはどこですか?
Uber, Instagram, Twitter, Pinterest, Forbes, Alibaba
Twitter、Instagram、Uber、Pinterest、Forbes、Alibabaなど、世界の多くの企業でプログレッシブウェブアプリが採用されています。
PWAを作成する時に必要なもの
プログレッシブウェブアプリを作成するには、最初にレスポンシブ対応のWebサイトを作成する必要があります。その後に、Web App ManifestとService Workerの2つが必要です。これらがどのようなものか見てましょう。
Web App Manifest
Web App ManifestはシンプルなJSONファイル「manifest.json」で、ブラウザにWebアプリとユーザーの動作を伝えます。
プロパティは下記の通りです。
- name: アプリのインストールプロンプトで使用される名前。
- short_name: ユーザーのホーム画面、ランチャー、スペースが限られている他の場所で使用される名前。
- start_url: 起動時にアプリを開始する場所をブラウザに指示します。
- display: アプリの起動時に表示されるブラウザUIをカスタマイズできます。最も使用される値はstandaloneです。Webアプリを開き、スタンドアロンのネイティブアプリのように表示します。
- background_color: アプリの起動時にスプラッシュ画面で使用されます。
- theme_color: ツールバーの色を設定します。
- orientation: 特定の方向を強制することができます。
- scope: 私は通常このプロパティを使用しませんが、ブラウザがアプリ内にあると見なすURLのセットを定義し、ユーザーがアプリを離れたタイミングを決定するためによく使用されます。
- icons: ユーザーがホーム画面にサイトを追加するときに、ブラウザが使用する一連の画像を定義できます。
Service Worker
これは基本的に、メインブラウザスレッドとは別に実行されるJavaScriptファイルで、Service Workerを使用して実行できます。
- ネットワーク リクエストの傍受する。
- キャッシュからリソースをキャッシュ・取得する。
- プッシュメッセージを配信する。
Service Workerのライフサイクル
- Registration: Service Workerの場所をブラウザに通知し、バックグラウンドでのインストールを開始する。
- Installation: Service Workerのインストール時にいくつかのタスクを実行できるインストールイベントをトリガーする。
- Activation: Service Workerによって制御されて開いているページがある場合、新しいService Workerは待機状態になります。新しいService Workerは、古いService Workerを使用しているページがロードされなくなった時にのみアクティブになり、一部のタスクの実行にも使用できます。
PWAを5分で構築しよう
では、プログレッシブウェブアプリを実装してみましょう。
実装の前にまずは、Lighthouseをインストールすることをお勧めします。
LighthouseはWebページの品質を向上させるためのツールで、下記のようなレポートを取得できます。
Lighthouseのレポート
このレポートからは、Webサイトやアプリのパフォーマンス、アクセシビリティ、ベストプラクティス、SEOおよびPWAを改善するために必要な問題を確認できます。
ファイル構造は、下記の通りです。
ファイル構造
Githubに完全なコードがあります。ブランチを切り替えて、動的キャッシュまたは静的キャッシュを表示できます。
index.htmlで、manifest.jsonを呼び出します。
1 |
<link rel="manifest" href="/manifest.json"> |
ただし、app.jsファイル(Service Workerを登録する場所)とPWAを最適化するために必要なメタタグも記述する必要があります。
1 2 3 4 |
<link rel="apple-touch-icon" href="/assets/images/logo-96x96.png"> <meta name="apple-mobile-web-app-status-bar" content="#FFE1C4"> <meta name="theme-color" content="#FFE1C4"> <script src="/assets/js/app.js"></script> |
メインのタグはこれで終了です、もちろんさらに多くのタグがあり、異なるパスを使用することもできます。
静的キャッシュ
はじめに、静的キャッシュから実装します。キャッシュにするリソース、画像やCSSやJavaScriptなどすべてを正確に手動で指定します。
この方法は特に、Webサイトのすべてのリソースをダウンロードし、ページの最初のランディング時にそれらのファイルをキャッシュする場合に便利です。
manifest.jsonに記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
{ "name": "Name Website", "short_name": "NameWebsite", "start_url": "/index.html", "display": "standalone", "background_color": "#F4F4F4", "theme_color": "#F4F4F4", "orientation": "portrait-primary", "icons": [ { "src": "/assets/images/logo-72x72.png", "type": "image/png", "sizes": "72x72" }, { "src": "/assets/images/logo-96x96.png", "type": "image/png", "sizes": "96x96" }, { "src": "/assets/images/logo-128x128.png", "type": "image/png", "sizes": "128x128" }, { "src": "/assets/images/logo-144x144.png", "type": "image/png", "sizes": "144x144" }, { "src": "/assets/images/logo-152x152.png", "type": "image/png", "sizes": "152x152" }, { "src": "/assets/images/logo-192x192.png", "type": "image/png", "sizes": "192x192" }, { "src": "/assets/images/logo-384x384.png", "type": "image/png", "sizes": "384x384" }, { "src": "/assets/images/logo-512x512.png", "type": "image/png", "sizes": "512x512" } ] } |
ブラウザがService Workerを許可しているかどうかを確認し、許可している場合はService Workerをapp.jsに登録します。
1 2 3 4 5 |
if('serviceWorker' in navigator){ navigator.serviceWorker.register('/sw.js') .then(reg => console.log('service worker registered')) .catch(err => console.log('service worker not registered', err)); } |
次に、sw.jsにService Workerを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const staticCacheName = 'site-static-v1'; const assets = [ '/', '/index.html', '/assets/js/ui.js', '/assets/css/main.css', '/assets/images/background-home.jpg', 'https://fonts.googleapis.com/css?family=Lato:300,400,700', ]; // install event self.addEventListener('install', evt => { evt.waitUntil( caches.open(staticCacheName).then((cache) => { console.log('caching shell assets'); cache.addAll(assets); }) ); }); // activate event self.addEventListener('activate', evt => { evt.waitUntil( caches.keys().then(keys => { return Promise.all(keys .filter(key => key !== staticCacheName) .map(key => caches.delete(key)) ); }) ); }); // fetch event self.addEventListener('fetch', evt => { evt.respondWith( caches.match(evt.request).then(cacheRes => { return cacheRes || fetch(evt.request); }) ); }); |
キャッシュに入れるすべてのリソースを配列に格納します。
Installイベント
キャッシュにすべての静的アセットを追加し、Chromeのコンソールで確認します。
キャッシュされているリソース
Activateイベント
キャッシュの名前を変更すると、複数のキャッシュが格納され、問題が発生する可能性があります。それを避けるために、古いものを削除する必要があります。この関数では、キー(キャッシュ名)をチェックし、同じキーが前のキーと異なる場合は、前のキーを削除します。これを行うと、常に最後のキャッシュのみが存在します。
Fetchイベント
ここでは、すでにキャッシュが存在するかどうかを確認します。キャッシュが存在する場合はリソースをダウンロードしませんが、キャッシュからリソースを取得してコンソールで再度確認できます。
Networkパネル
Service Workerファイルを変更する時は、キャッシュの名前を変更する必要があります。これによりService Workerを更新し、新しいキャッシュを作成できます。
動的キャッシュ
動的キャッシュはナビゲーション中にすべてのFetchリクエストを自動的にキャッシュするため、非常に強力です。ただし、このキャッシュはAPIで呼び出しがある時に使用すると、新しいデータが変更されても反映されないため、慎重に使用する必要があります。
動的キャッシュを使用するには、sw.jsファイルを変更する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
const dynamicCacheName = 'site-dynamic-v1'; // activate event self.addEventListener('activate', evt => { evt.waitUntil( caches.keys().then(keys => { return Promise.all(keys .filter(key => key !== dynamicCacheName) .map(key => caches.delete(key)) ); }) ); }); // fetch event self.addEventListener('fetch', evt => { evt.respondWith( caches.match(evt.request).then(cacheRes => { return cacheRes || fetch(evt.request).then(fetchRes => { return caches.open(dynamicCacheName).then(cache => { cache.put(evt.request.url, fetchRes.clone()); return fetchRes; }) }); }) ); }); |
Activateイベント
ここでは、静的キャッシュと同じことをします。
Fetchイベント
Fetchイベントでは、すべてのFetchリクエストを自動的にキャッシュに入れます。
キャッシュとLighthouseの実行後に両方を試すと、Webサイトがプログレッシブウェブアプリであることが分かります。
PWA Lighthouse
静的キャッシュと動的キャッシュのコードは下記からダウンロードできます。
静的と動的のどちらを使用すべきですか?
その答えは、ニーズとプロジェクトによって異なります。API呼び出しがない場合は動的キャッシュを使用します。逆にAPI呼び出しがある場合は静的キャッシュに保存するリソースを自分で選択できます。
Googleによるプログレッシブウェブアプリの詳細については、下記をご覧ください。
sponsors