A Beginner’s Guide To Progressive Web Apps
著者について
Kevin Farrugiaは、Incredible Webの共同創設者です。Incredible Web.comの共同創立者です。 & ヨーロッパのマルタに拠点を置くモバイルアプリケーション開発会社です。
- 18分で読める
- モバイル、アプリ、AMP、サービスワーカー
- オフラインで読めるように保存されている
- Twitterでシェアする。 LinkedIn
プログレッシブウェブアプリは、モバイルウェブの次の大きな流れになるかもしれません。
Further Reading on SmashingMag:
- The Building Blocks Of Progressive Web Apps
- Conversational Design Essentials:
- Building A First-Class App That Leverages Your Website
- Creating A Complete Web App In Foundation For Apps
プログレッシブWebアプリケーションは、最新のテクノロジーを活用して、Webとモバイルアプリの長所を組み合わせたものです。 ウェブ技術を使って構築されたウェブサイトでありながら、アプリのように動作し、感じられるものだと考えてください。
プログレッシブWebアプリケーションは、より大規模なWebエコシステム、プラグイン、コミュニティを活用し、各アプリストアのネイティブアプリケーションと比較して、Webサイトのデプロイとメンテナンスが比較的容易であることを利用しています。 モバイルとウェブの両方で開発を行っている方にとっては、ウェブサイトがより短時間で構築できること、API が後方互換性を維持する必要がないこと (ネイティブ アプリのバージョンの断片化とは異なり、すべてのユーザーがウェブサイトのコードの同じバージョンを実行する)、そしてアプリの展開と維持が一般的に容易であることを評価していただけると思います。
なぜProgressive Web Appsなのか
ある調査によると、ユーザーが初めてアプリに触れてからアプリを使い始めるまでの間に、アプリは平均して20%のユーザーを失うといいます。 ユーザーは、まずアプリストアでアプリを見つけ、ダウンロードし、インストールし、最後にアプリを開かなければなりません。 あなたのプログレッシブウェブアプリを見つけたユーザーは、すぐに使い始めることができ、不要なダウンロードやインストールの段階を省くことができます。
とはいえ、ネイティブ アプリがすべて悪いわけではありません。 プッシュ通知を備えたモバイルアプリケーションは、プッシュがないものに比べて最大3倍のリテンションを達成しており、ユーザーがモバイルアプリケーションを再度開く可能性は、Webサイトよりも3倍高いと言われています。
プログレッシブ Web アプリケーションは、モバイル アプリケーションの特性を活かし、モバイル アプリケーションの維持に伴う複雑さを伴わずに、ユーザーの維持とパフォーマンスの向上をもたらします。
使用例
どのような場合にプログレッシブ Web アプリケーションを構築すべきでしょうか。 ネイティブは通常、ユーザーが頻繁に戻ってくることが予想されるアプリケーションに推奨されますが、プログレッシブ ウェブ アプリも同様です。
次のアプリケーションがプログレッシブWebアプリ、Webサイト、ネイティブモバイルアプリケーションのどれにすべきかを評価する際には、まずユーザーと最も重要なユーザーアクションを特定します。
プログレッシブウェブアプリは「プログレッシブ」であるため、すべてのブラウザで動作し、ユーザーのブラウザが新しく改良された機能やAPIで更新されるたびに、エクスペリエンスが向上します。
ユーザーの重要なアクションに特定の機能が必要だが、クロスブラウザがサポートされていないためにまだ利用できない場合は、すべてのユーザーに同じエクスペリエンスを保証するネイティブ モバイル アプリケーションがよりよい選択肢となるでしょう。
プログレッシブ Web アプリの特徴
コードを書き始める前に、プログレッシブ Web アプリには次のような特徴があることを理解しておくことが重要です。 定義によれば、プログレッシブ ウェブ アプリはあらゆるデバイスで動作し、ユーザーのデバイスやブラウザで利用可能なあらゆる機能を活用しながら、徐々に機能を向上させていかなければなりません。
Let’s Code!
私たちの最初のプログレッシブ Web アプリ「Sky High」は、空港の到着スケジュールをシミュレートします。 ユーザーが初めてこのウェブ アプリにアクセスしたとき、API から取得した今後のフライトのリストを表示したいと思います。 ユーザーがインターネットに接続していないときに Web アプリを再読み込みすると、接続しているときに最後にダウンロードしたときのフライト スケジュールを表示したいと思います。
基礎編
プログレッシブWebアプリの第一の特徴は、すべてのデバイスで動作し、それを許容するデバイスやブラウザでは機能拡張しなければならないことです。 そのため、伝統的なHTML5を使用し、モックAPIからのデータ取得をシミュレートするJavaScriptを用いてウェブサイトを構築しました。 このアプリケーションでは、Model-View-ViewModel(MVVM)バインディングを処理するために、Knockoutの一部を使用しています。Knockoutは、JavaScriptのモデルをHTMLのビューにバインドすることができる軽量のJavaScriptフレームワークです。
私たちのウェブサイトは、デザインとインタラクションを導く一連の原則である、Googleのマテリアルデザインガイドラインに従っています。 マテリアルデザインは、アプリケーションやデバイス間で統一された基準となるだけでなく、デザインに意味を与えます。
最後に、ジャンクフリーであること、スクロールがスムーズであることを確認するために、アプリをテストしました。 ジャンクのないレンダリングは、ユーザーのエンゲージメントを向上させることがわかっています。
このデモでは、実際のAPIではなく、静的なJSONファイルを取得します。 これは単に物事をシンプルにするためです。
index.html
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Sky-High Airport Arrivals</title> <link async rel="stylesheet" href="./css/style.css"> <link href="https://fonts.googleapis.com/css?family=Roboto:300,600,300italic,600italic" rel="stylesheet" type="text/css"></head><body> <header> <div class="content"> <h3>Arrivals</h3> </div> </header> <div class="container"> <div class="content"> <ul class="arrivals-list" data-bind="foreach: arrivals"> <li class="item"> <span class="title" data-bind="html: title"></span> <span class="status" data-bind="html: status"></span> <span class="time" data-bind="html: time"></span> </li> </ul> </div> </div> <script src="./js/build/vendor.min.js"></script> <script src="./js/build/script.min.js"></script></body></html>
index.html
ファイルは比較的標準的なものです。 HTMLリストを作成し、ビューモデルのプロパティarrivals
data-bind="foreach: arrivals”
を介して、Knockoutを使ってバインドしています。 View Model arrivals
page.js
Page
モジュールで公開されています。 HTMLページでは、arrivals
title
status
time
のプロパティをHTMLビューにバインドしています。js
(var Page = (function() { // declare the view model used within the page function ViewModel() { var self = this; self.arrivals = ko.observableArray(); } // expose the view model through the Page module return { vm: new ViewModel(), hideOfflineWarning: function() { // enable the live data document.querySelector(".arrivals-list").classList.remove('loading') // remove the offline message document.getElementById("offline").remove(); // load the live data }, showOfflineWarning: function() { // disable the live data document.querySelector(".arrivals-list").classList.add('loading') // load html template informing the user they are offline var request = new XMLHttpRequest(); request.open('GET', './offline.html', true); request.onload = function() { if (request.status === 200) { // success // create offline element with HTML loaded from offline.html template var offlineMessageElement = document.createElement("div"); offlineMessageElement.setAttribute("id", "offline"); offlineMessageElement.innerHTML = request.responseText; document.getElementById("main").appendChild(offlineMessageElement); } else { // error retrieving file console.warn('Error retrieving offline.html'); } }; request.onerror = function() { // network errors console.error('Connection error'); }; request.send(); } }})();
このpage.js
Page
モジュールを公開しています。 このモジュールには、ViewModel vm
hideOfflineWarning
showOfflineWarning
ViewModel
は、アプリケーション全体で使用されるシンプルなJavaScriptリテラルです。 ViewModelのプロパティarrivals
は、KnockoutのobservableArray
であり、HTMLをJavaScriptの配列に自動的にバインドし、JavaScriptで配列にアイテムをプッシュしたりポップしたりして、ページのHTMLを自動的に更新することができます。
関数の hideOfflineWarning
showOfflineWarning
により、アプリケーションの残りの部分がこれらの関数を呼び出して、オンラインで接続されているかどうかを表示するページの UI を更新することができます。 showOfflineWarning
loading
arrivals-list
のHTML要素に追加してリストをフェードアウトさせ、XHRを介してHTMLファイルoffline.html
response.status === 200
)、これをHTMLに追加します。 もちろん、サービスワーカーを使用しておらず、ユーザーがインターネットに接続されていない場合は、offline.html
を取得することができないため、ユーザーはブラウザのオフラインページを見ることになります。
APIからデータを取得し、それをView ModelsやViewsにバインドするビジネスロジックは、arrivals.js
にあり、Knockoutを使った標準的なMVVM機能です。 arrivals.js
Arrivals.loadData()
を公開しています。
Web アプリ マニフェスト
Web アプリをよりアプリらしくしましょう。 Webアプリのマニフェストファイルは、W3Cの仕様に従ったシンプルなJSONファイルです。 これを使うと、ウェブアプリをスタンドアロンのアプリケーションとしてフルスクリーンモードで実行したり、アプリケーションがデバイスにインストールされたときに表示されるアイコンを割り当てたり、アプリにテーマや背景色を割り当てたりすることができます。 さらに、Chrome on Androidでは、ウェブアプリのインストールバナーを使って、ユーザーにウェブアプリのインストールを積極的に提案します。
- 有効なウェブ アプリ マニフェスト ファイルを持っていること、
- HTTPS で提供されていること、
- 有効なサービス ワーカーが登録されていること、
- 各訪問の間に少なくとも 5 分の間隔を置いて 2 回訪問されていること。
manifest.json
{ "short_name": "Arrivals", "name": "Arrivals at Sky High", "description": "Progressive web application demonstration", "icons": , "start_url": "./?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "theme_color": "#29BDBB", "background_color": "#29BDBB"}
このマニフェストファイルを分解してみましょう:
-
short_name
は、アプリケーションの人間が読める名前です。 -
name
は、アプリケーションの人間が読める名前で、アプリケーションがどのように表示されるかを定義します。 -
description
は、ウェブ アプリケーションの一般的な説明を提供します。 -
icons
は、アプリケーションのアイコン セットとして機能する、さまざまなサイズの画像の配列を定義します。 -
start_url
は、アプリケーションの開始URLです。 -
display
は、ウェブアプリケーションのデフォルトの表示モードを定義します。 -
fullscreen
standalone
minimal-ui
browser
. -
orientation
は、Webアプリケーションのデフォルトの向きを定義します。 -
theme_color
は、アプリケーションのデフォルトのテーマカラーです。 -
background_color
は、Web アプリケーションの背景色を定義します。 -
related_applications
は、この例では実装されていませんが、さまざまなアプリ ストアでネイティブ アプリケーションの代替を指定するために使用されます。
manifest.json
index.html
head
タグに追加します。
<link rel="manifest" href="./manifest.json">
ユーザーがウェブ アプリをホーム画面に追加すると、ブラウザを直接開くことなく、デバイスからすぐにアプリケーションに再アクセスできるようになります。
Add to Homescreen on Chrome for Android from Smashing Magazine on Vimeo.をご覧ください。
サービスワーカー
プログレッシブウェブアプリのよりエキサイティングな側面の1つは、オフラインで動作することです。 サービス ワーカーを使用すると、アプリの以前のセッションで取得したデータを表示したり (IndexedDB を使用)、アプリケーション シェルを表示してユーザーにインターネットに接続されていないことを通知したりすることができます (このデモではこのアプローチを採用しています)。
これらはすべてサービス ワーカーによって実現されています。サービス ワーカーとは、ネットワークの取得を含むドメイン全体のイベントにアクセスできる、イベント ドリブンのスクリプト (JavaScript で記述) です。
アプリケーション シェル
アプリケーション シェルは、ユーザー インターフェイスを動かすために必要な最小限の HTML、CSS、JavaScript です。 ネイティブ モバイル アプリケーションは、アプリケーション シェルを配布物の一部として含みますが、Web サイトは通常、ネットワークを介してこれを要求します。 プログレッシブWebアプリケーションは、アプリケーションシェルのリソースやアセットをブラウザのキャッシュに格納することで、このギャップを解消します。 今回のSky Highアプリケーションでは、アプリケーションシェルは、トップヘッダーバー、フォント、およびこれらをエレガントにレンダリングするために必要なCSSで構成されていることがわかります。
サービス ワーカーを使い始めるには、まずサービス ワーカーの JavaScript ファイル sw.js
をルート ディレクトリに作成する必要があります。
sw.js
// Use a cacheName for cache versioningvar cacheName = 'v1:static';// During the installation phase, you'll usually want to cache static assets.self.addEventListener('install', function(e) { // Once the service worker is installed, go ahead and fetch the resources to make this work offline. e.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll().then(function() { self.skipWaiting(); }); }) );});// when the browser fetches a URL…self.addEventListener('fetch', function(event) { // … either respond with the cached object or go ahead and fetch the actual URL event.respondWith( caches.match(event.request).then(function(response) { if (response) { // retrieve from cache return response; } // fetch as normal return fetch(event.request); }) );});
サービス ワーカーを詳しく見てみましょう。 まず、cacheName
という変数を設定しています。 これは、キャッシュされたアセットに変更が加えられたかどうかを判断するために使用します。
self.addEventListener('install', function(e) { // declare which assets to cache}
install
イベントは、サービス ワーカーのインストール段階で発生し、サービス ワーカーがすでにインストールされている場合は 1 回だけ発生します。 そのため、ページを更新してもインストールフェーズが再度発生することはありません。 インストールフェーズでは、どのアセットをキャッシュするかを宣言することができます。 上の例では、1つのCSSファイル、2つのJavaScriptファイル、フォントファイル、オフラインのHTMLテンプレート、そしてもちろん、アプリケーションルートをキャッシュしています。 self.skipWaiting()
待機中のサービス ワーカーを強制的にアクティブにします。
ここまでで、サービス ワーカーを宣言しましたが、その効果を確認する前に、JavaScript で参照する必要があります。 今回のアプリケーションでは main.js
// Register the service worker if available.if ('serviceWorker' in navigator) { navigator.serviceWorker.register('./sw.js').then(function(reg) { console.log('Successfully registered service worker', reg); }).catch(function(err) { console.warn('Error whilst registering service worker', err); });}window.addEventListener('online', function(e) { // Resync data with server. console.log("You are online"); Page.hideOfflineWarning(); Arrivals.loadData();}, false);window.addEventListener('offline', function(e) { // Queue up events for server. console.log("You are offline"); Page.showOfflineWarning();}, false);// Check if the user is connected.if (navigator.onLine) { Arrivals.loadData();} else { // Show offline message Page.showOfflineWarning();}// Set Knockout view model bindings.ko.applyBindings(Page.vm);
また、セッションの状態が online
offline
Arrivals.loadData()
Page.showOfflineWarning
Page.hideOfflineWarning
を、それぞれ異なる関数で呼び出します。 また、navigator.onLineを使ってユーザーが現在オンラインであるかどうかを確認し、それに応じてデータを取得したり、オフラインの警告を表示したりしています。
初めてアプリケーションを(Chrome Developer Toolsで)読み込むと、新しいものは何も表示されません。 しかし、リロードすると、サービス ワーカーからいくつかのネットワーク リソースが取得されていることがわかります。 これがアプリケーションのシェルです。
Offline Test
ユーザーがインターネットに接続していない状態でアプリケーションを実行すると (すでにページにアクセスしていると仮定して)、アプリケーション シェルとオフラインの警告が表示されるだけで、Chrome の徘徊する T-REX よりも改善されます。 ユーザーがネットワーク接続を確立すると、警告を無効にして最新のデータを取得します。
The Guardian は、オフライン ユーザーが同社のウェブサイトにアクセスする際に、クロスワード パズルを提供するという、特に興味深いアプローチを取っています。
プッシュ通知
プッシュ通知は、ユーザーが信頼するアプリケーションからのタイムリーなアップデートを受け取ることができるようにするものです。 プッシュ通知は、ユーザーが信頼しているアプリケーションからのタイムリーな更新情報を受け取ることができ、そのアプリケーションとの関係を深めるのに役立ちます。 ウェブ上のプッシュ通知では、ブラウザを閉じていてもユーザーとのつながりを保つことができます。
プッシュAPIは、Chrome、Opera、Samsungのブラウザでサポートされており、FirefoxとMicrosoft Edgeでは開発中です。
パフォーマンス
サービスワーカーの最も簡単な利点の1つは、ほとんど努力せずにパフォーマンスを改善できることです。 サービス ワーカーが実装される前の Web サイトと比較すると、以前はページ ロード時に 200 KB 以上を取得していましたが、現在は 13 KB にまで減少しています。
このようにパフォーマンスが劇的に向上したのは、アプリケーション自体が非常に小さく、機能も限られているからです。
Lighthouse
Google の Chrome チームは、プログレッシブ ウェブ アプリをテストするためのツールをまとめました。
Lighthouse のテストを実行するには、ウェブサイトがオンラインで利用可能である必要があります。つまり、localhost
ではテストできません。
まず、npmパッケージをダウンロードします:
npm install -g GoogleChrome/lighthouse
インストールが完了したら、Chrome(バージョン52以降)を起動します。
npm explore -g lighthouse -- npm run chromelighthouse https://incredibleweb.github.io/pwa-tutorial/
Lighthouse の実行結果はコマンド ラインで表示され、実装したプログレッシブ ウェブ アプリの機能やプロパティ (たとえば、manifest.json
ファイルを使用しているかどうかや、ページがオフラインで利用可能かどうかなど) に応じて Web サイトが評価されます。
おわりに
この記事はプログレッシブ ウェブ アプリの前菜にすぎません。
クロス ブラウザー サポート
プログレッシブ ウェブ アプリはまだ初期段階であり、クロスブラウザー サポートは、特に Safari と Edge ではまだ限られています。
- サービス ワーカーとキャッシュ API。 Chrome、Firefox、Opera、Samsungのブラウザでサポートされています。 Microsoft Edgeでは開発中で、2016年末には利用可能になる見込み。 Safariでは検討中。
- ホーム画面に追加。 Chrome、Firefox、Opera、Android Browser、Samsungのブラウザでサポート。 マイクロソフトは、プログレッシブウェブアプリがストアリストとして利用できるようになることを示しているようです。 Safari にはまだ予定がありません。
- Push API。 Chrome、Firefox、Opera、Samsungのブラウザでほとんどサポートされています。 Microsoft Edgeでは開発中。
より多くの開発者が、比較的簡単に実装でき、すぐに効果が得られるプログレッシブウェブアプリの機能を利用するようになれば、ユーザーはサポートされているブラウザでこれらのウェブアプリを利用することを好むようになり、うまくいけば他のブラウザベンダーもそれに対応するようになるかもしれません。