Articles

A Beginner’s Guide To Progressive Web Apps

Kevin Farrugia

著者について

Kevin Farrugiaは、Incredible Webの共同創設者です。Incredible Web.comの共同創立者です。 & ヨーロッパのマルタに拠点を置くモバイルアプリケーション開発会社です。

  • 18分で読める
  • モバイル、アプリ、AMP、サービスワーカー
  • オフラインで読めるように保存されている
  • Twitterでシェアする。 LinkedIn
PWAは最新のテクノロジーを活用して、ウェブアプリとモバイルアプリの長所を組み合わせたものです。

プログレッシブウェブアプリは、モバイルウェブの次の大きな流れになるかもしれません。

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 アプリには次のような特徴があることを理解しておくことが重要です。 定義によれば、プログレッシブ ウェブ アプリはあらゆるデバイスで動作し、ユーザーのデバイスやブラウザで利用可能なあらゆる機能を活用しながら、徐々に機能を向上させていかなければなりません。

  • 発見可能。 プログレッシブウェブアプリはウェブサイトなので、検索エンジンで発見できるはずです。 これは、検索性において Web サイトにまだ遅れをとっているネイティブ アプリケーションに比べて大きな利点です。 Web サイトから継承されたもう 1 つの特性として、優れたデザインの Web サイトでは、アプリケーションの現在の状態を示すために URI を使用する必要があります。 これにより、ユーザーがアプリの URL をブックマークまたは共有したときに、ウェブ アプリがその状態を保持または再読み込みできるようになります。
  • レスポンシブ。 プログレッシブウェブアプリの UI は、デバイスのフォームファクターとスクリーンサイズに適合しなければなりません。
  • アプリライク。 プログレッシブウェブアプリはネイティブアプリのように見え、アプリケーションシェルモデルに基づいて構築され、ページの更新が最小限であること。
  • 接続性に依存しない。 接続性の低い地域やオフラインでも動作する必要があります(私たちのお気に入りの特性です)。
  • 再エンゲージメント可能。 モバイルアプリのユーザーは、アプリを再利用する可能性が高く、プログレッシブウェブアプリは、プッシュ通知などの機能を通じて同じ目標を達成することを目的としています。
  • インストール可能。 プログレッシブウェブアプリは、デバイスのホーム画面にインストールすることで、すぐに利用できるようになります。
  • フレッシュ。 新しいコンテンツが公開され、ユーザーがインターネットに接続している場合、そのコンテンツはアプリ内で利用可能であるべきです。
  • 安全。
  • Let’s Code!

    私たちの最初のプログレッシブ Web アプリ「Sky High」は、空港の到着スケジュールをシミュレートします。 ユーザーが初めてこのウェブ アプリにアクセスしたとき、API から取得した今後のフライトのリストを表示したいと思います。 ユーザーがインターネットに接続していないときに Web アプリを再読み込みすると、接続しているときに最後にダウンロードしたときのフライト スケジュールを表示したいと思います。

    Sky Highのスクリーンショット
    Sky High,

    基礎編

    プログレッシブ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リストを作成し、ビューモデルのプロパティarrivalsdata-bind="foreach: arrivals”を介して、Knockoutを使ってバインドしています。 View Model arrivalspage.jsPageモジュールで公開されています。 HTMLページでは、arrivalstitlestatustimeのプロパティを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.jsPageモジュールを公開しています。 このモジュールには、ViewModel vmhideOfflineWarningshowOfflineWarningViewModelは、アプリケーション全体で使用されるシンプルなJavaScriptリテラルです。 ViewModelのプロパティarrivalsは、KnockoutのobservableArrayであり、HTMLをJavaScriptの配列に自動的にバインドし、JavaScriptで配列にアイテムをプッシュしたりポップしたりして、ページのHTMLを自動的に更新することができます。

    関数の hideOfflineWarningshowOfflineWarning により、アプリケーションの残りの部分がこれらの関数を呼び出して、オンラインで接続されているかどうかを表示するページの UI を更新することができます。 showOfflineWarningloadingarrivals-listのHTML要素に追加してリストをフェードアウトさせ、XHRを介してHTMLファイルoffline.htmlresponse.status === 200)、これをHTMLに追加します。 もちろん、サービスワーカーを使用しておらず、ユーザーがインターネットに接続されていない場合は、offline.htmlを取得することができないため、ユーザーはブラウザのオフラインページを見ることになります。

    APIからデータを取得し、それをView ModelsやViewsにバインドするビジネスロジックは、arrivals.jsにあり、Knockoutを使った標準的なMVVM機能です。 arrivals.jsArrivals.loadData() を公開しています。

    Web アプリ マニフェスト

    Web アプリをよりアプリらしくしましょう。 Webアプリのマニフェストファイルは、W3Cの仕様に従ったシンプルなJSONファイルです。 これを使うと、ウェブアプリをスタンドアロンのアプリケーションとしてフルスクリーンモードで実行したり、アプリケーションがデバイスにインストールされたときに表示されるアイコンを割り当てたり、アプリにテーマや背景色を割り当てたりすることができます。 さらに、Chrome on Androidでは、ウェブアプリのインストールバナーを使って、ユーザーにウェブアプリのインストールを積極的に提案します。

    • 有効なウェブ アプリ マニフェスト ファイルを持っていること、
    • HTTPS で提供されていること、
    • 有効なサービス ワーカーが登録されていること、
    • 各訪問の間に少なくとも 5 分の間隔を置いて 2 回訪問されていること。
    Webアプリのインストールバナー
    Webアプリのインストールバナー(大きなサイズで表示)

    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 は、ウェブアプリケーションのデフォルトの表示モードを定義します。
    • fullscreenstandaloneminimal-uibrowser.
    • orientationは、Webアプリケーションのデフォルトの向きを定義します。
    • theme_color は、アプリケーションのデフォルトのテーマカラーです。
    • background_color は、Web アプリケーションの背景色を定義します。
    • related_applications は、この例では実装されていませんが、さまざまなアプリ ストアでネイティブ アプリケーションの代替を指定するために使用されます。

    manifest.jsonindex.htmlheadタグに追加します。

    <link rel="manifest" href="./manifest.json">

    ユーザーがウェブ アプリをホーム画面に追加すると、ブラウザを直接開くことなく、デバイスからすぐにアプリケーションに再アクセスできるようになります。

    Add to Homescreen on Chrome for Android from Smashing Magazine on Vimeo.をご覧ください。

    Android版Chromeでホーム画面に追加する

    サービスワーカー

    プログレッシブウェブアプリのよりエキサイティングな側面の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);

    また、セッションの状態が onlineofflineArrivals.loadData()Page.showOfflineWarningPage.hideOfflineWarning を、それぞれ異なる関数で呼び出します。 また、navigator.onLineを使ってユーザーが現在オンラインであるかどうかを確認し、それに応じてデータを取得したり、オフラインの警告を表示したりしています。

    初めてアプリケーションを(Chrome Developer Toolsで)読み込むと、新しいものは何も表示されません。 しかし、リロードすると、サービス ワーカーからいくつかのネットワーク リソースが取得されていることがわかります。 これがアプリケーションのシェルです。

    アプリケーションシェル
    アプリケーションシェルのネットワークリソースです。 in Chrome Developer Tools (View big version)

    Offline Test

    ユーザーがインターネットに接続していない状態でアプリケーションを実行すると (すでにページにアクセスしていると仮定して)、アプリケーション シェルとオフラインの警告が表示されるだけで、Chrome の徘徊する T-REX よりも改善されます。 ユーザーがネットワーク接続を確立すると、警告を無効にして最新のデータを取得します。

    Failing gracefully
    Chrome のデフォルト ページの代わりにカスタム HTML ページをレンダリングする (大きいバージョンを表示)

    The Guardian は、オフライン ユーザーが同社のウェブサイトにアクセスする際に、クロスワード パズルを提供するという、特に興味深いアプローチを取っています。

    The Guardian's offline crossword puzzle's offline crossword puzzle
    The Guardian’s offline crossword puzzle (View large

    プッシュ通知

    プッシュ通知は、ユーザーが信頼するアプリケーションからのタイムリーなアップデートを受け取ることができるようにするものです。 プッシュ通知は、ユーザーが信頼しているアプリケーションからのタイムリーな更新情報を受け取ることができ、そのアプリケーションとの関係を深めるのに役立ちます。 ウェブ上のプッシュ通知では、ブラウザを閉じていてもユーザーとのつながりを保つことができます。

    プッシュ通知

    プッシュ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では開発中。

    より多くの開発者が、比較的簡単に実装でき、すぐに効果が得られるプログレッシブウェブアプリの機能を利用するようになれば、ユーザーはサポートされているブラウザでこれらのウェブアプリを利用することを好むようになり、うまくいけば他のブラウザベンダーもそれに対応するようになるかもしれません。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です