Webpackとワークボックスを使用してPWAを構築する
公開: 2022-03-10プログレッシブウェブアプリ(PWA)は、最新のテクノロジーを使用してウェブ上でアプリのようなエクスペリエンスを提供するサイトです。 これは、「Webアプリマニフェスト」、「サービスワーカー」などの新しいテクノロジーの総称です。 これらのテクノロジーを組み合わせることで、Webサイトで高速で魅力的なユーザーエクスペリエンスを提供できます。
この記事は、既存の1ページのWebサイトにサービスワーカーを追加するためのステップバイステップのチュートリアルです。 Service Workerを使用すると、Webサイトをオフラインで機能させると同時に、サイトの更新をユーザーに通知できます。 これはWebpackにバンドルされている小さなプロジェクトに基づいているため、Workbox Webpackプラグイン(Workbox v4)を使用することに注意してください。
ツールを使用してServiceWorkerを生成することは、キャッシュを効率的に管理できるため、推奨されるアプローチです。 このチュートリアルでは、Workbox(Service Workerコードの生成を容易にするライブラリのセット)を使用して、ServiceWorkerを生成します。
プロジェクトに応じて、3つの異なる方法でWorkboxを使用できます。
- ワークボックスを任意のアプリケーションに統合できるコマンドラインインターフェイスを利用できます。
- Node.jsモジュールを使用すると、ワークボックスをgulpやgruntなどの任意のノードビルドツールに統合できます。
- Webpackで構築されたプロジェクトと簡単に統合できるWebpackプラグインが利用可能です。
Webpackはモジュールバンドラーです。 簡単にするために、JavaScriptの依存関係を管理するツールと考えることができます。 これにより、ライブラリからJavaScriptコードをインポートし、JavaScriptを1つまたは複数のファイルにバンドルできます。
開始するには、コンピューターに次のリポジトリのクローンを作成します。
git clone [email protected]:jadjoubran/workbox-tutorial-v4.git cd workbox-tutorial-v4 npm install npm run dev
次に、 https://localhost:8080/
に移動します。 このチュートリアル全体で使用する通貨アプリを確認できるはずです。
アプリシェルから始める
アプリケーションシェル(または「アプリシェル」)は、ネイティブアプリから着想を得たパターンです。 アプリをよりネイティブな外観にするのに役立ちます。 これは、データのないレイアウトと構造をアプリに提供するだけです。これは、Webアプリの読み込みエクスペリエンスを向上させることを目的とした移行画面です。
ネイティブアプリのアプリシェルの例を次に示します。
PWAのアプリシェルの例は次のとおりです。
ユーザーは、空白の画面を軽蔑するため、アプリシェルの読み込みエクスペリエンスを好みます。 空白の画面は、ユーザーにWebサイトがロードされていないことを感じさせます。 それは彼らにウェブサイトが立ち往生しているように感じさせます。
アプリシェルは、ナビゲーションバー、タブバー、リクエストしたコンテンツが読み込まれていることを示すローダーなど、アプリのナビゲーション構造をできるだけ早くペイントしようとします。
では、どのようにしてアプリシェルを構築しますか?
アプリのシェルパターンは、最初にレンダリングされるHTML、CSS、JavaScriptの読み込みを優先します。 つまり、これらのリソースを完全に優先する必要があるため、これらのアセットをインライン化する必要があります。 したがって、アプリシェルを構築するには、アプリシェルを担当するHTML、CSS、JavaScriptをインライン化する必要があります。 もちろん、すべてをインライン化するのではなく、合計で約30〜40KBの制限内にとどまる必要があります。
インライン化されたアプリシェルはindex.htmlで確認できます。 index.htmlファイルをチェックアウトすることでソースコードを検査でき、開発ツールで<main>
要素を削除することでブラウザでプレビューできます。
オフラインで動作しますか?
オフラインになることをシミュレートしましょう! DevToolsを開き、[ネットワーク]タブに移動して、[オフライン]チェックボックスをオンにします。 ページをリロードすると、ブラウザのオフラインページが表示されます。
これは、インターネットがオフラインであるため、 /
への最初の要求( index.htmlファイルをロードします)が失敗するためです。 その要求の失敗から回復する唯一の方法は、サービスワーカーを配置することです。
サービスワーカーなしでリクエストを視覚化してみましょう。
サービスワーカーはプログラム可能なネットワークプロキシです。つまり、サービスワーカーはWebページとインターネットの間に位置します。 これにより、着信および発信ネットワーク要求を制御できます。
これは、この失敗したリクエストをキャッシュに再ルーティングできるため、有益です(キャッシュにコンテンツがあると仮定します)。
Service Workerも一種のWebWorkerです。つまり、メインページとは別に実行され、 window
またはdocument
オブジェクトにアクセスできません。
AppShellをプリキャッシュする
アプリをオフラインで動作させるために、アプリシェルをプリキャッシュすることから始めます。
それでは、WebpackWorkboxプラグインをインストールすることから始めましょう。
npm install --save-dev workbox-webpack-plugin
次に、 index.jsファイルを開き、サービスワーカーを登録します。
if ("serviceWorker" in navigator){ window.addEventListener("load", () => { navigator.serviceWorker.register("/sw.js"); }) }
次に、 webpack.config.jsファイルを開き、Workboxwebpackプラグインを構成しましょう。
//add at the top const WorkboxWebpackPlugin = require("workbox-webpack-plugin"); //add inside the plugins array: plugins: [ … , new WorkboxWebpackPlugin.InjectManifest({ swSrc: "./src/src-sw.js", swDest: "sw.js" }) ]
これにより、。 / src /src-sw.jsファイルをベースとして使用するようにWorkboxに指示されます。 生成されたファイルはsw.jsと呼ばれ、 dist
フォルダーにあります。
次に、ルートレベルで./src/src-sw.jsファイルを作成し、その中に次のように記述します。
workbox.precaching.precacheAndRoute(self.__precacheManifest);
注: self.__precacheManifest
変数は、ワークボックスによって動的に生成されるファイルからインポートされます。
これで、 npm run build
を使用してコードをビルドする準備が整い、Workboxはdist
フォルダー内に2つのファイルを生成します。
- precache-manifest.66cf63077c7e4a70ba741ee9e6a8da29.js
- sw.js
sw.jsは、CDNおよびprecache-manifest。[chunkhash] .jsからワークボックスをインポートします。
//precache-manifest.[chunkhash].js file self.__precacheManifest = (self.__precacheManifest || []).concat([ "revision": "ba8f7488757693a5a5b1e712ac29cc28", "url": "index.html" }, "url": "main.49467c51ac5e0cb2b58e.js" ]);
precacheマニフェストには、webpackによって処理され、最終的にdist
フォルダーに格納されるファイルの名前が一覧表示されます。 これらのファイルを使用して、ブラウザにプリキャッシュします。 これは、Webサイトが最初にロードされ、Service Workerを登録するときに、次回使用できるようにこれらのアセットをキャッシュすることを意味します。
また、一部のエントリには「リビジョン」があり、他のエントリにはないことに注意してください。 これは、ファイル名のチャンクハッシュからリビジョンを推測できる場合があるためです。 たとえば、ファイル名main.49467c51ac5e0cb2b58e.jsを詳しく見てみましょう。 ファイル名にリビジョンがあります。これはchunkhash49467c51ac5e0cb2b58eです。
これにより、Workboxはファイルがいつ変更されたかを認識できるため、新しいバージョンのService Workerを公開するたびにすべてのキャッシュをダンプするのではなく、変更されたファイルのみをクリーンアップまたは更新します。
ページを初めてロードするときに、ServiceWorkerがインストールされます。 あなたはDevToolsでそれを見ることができます。 最初にsw.jsファイルが要求され、次に他のすべてのファイルが要求されます。 それらは歯車のアイコンではっきりとマークされています。
そのため、Workboxは初期化され、precache-manifestにあるすべてのファイルをprecacheします。 .mapファイルやアプリシェルの一部ではないファイルなど、 precache-manifestファイルに不要なファイルがないことを再確認することが重要です。
[ネットワーク]タブでは、ServiceWorkerからのリクエストを確認できます。 そして今、あなたがオフラインにしようとすると、アプリシェルはすでに事前にキャッシュされているので、オフラインでも機能します!
動的ルートのキャッシュ
オフラインにすると、アプリシェルは機能しますが、データは機能しないことに気づきましたか? これは、これらのAPI呼び出しが事前にキャッシュされたアプリシェルの一部ではないためです。 インターネットに接続されていない場合、これらのリクエストは失敗し、ユーザーは通貨情報を見ることができなくなります。
ただし、これらのリクエストはAPIからの値であるため、事前にキャッシュすることはできません。 さらに、複数のページが作成され始めた場合、すべてのAPIリクエストを一度にキャッシュする必要はありません。 代わりに、ユーザーがそのページにアクセスしたときにそれらをキャッシュする必要があります。
これらを「動的データ」と呼びます。 多くの場合、API呼び出しや、ユーザーがWebサイトで特定のアクションを実行したとき(たとえば、新しいページを参照したとき)に要求される画像やその他のアセットが含まれます。
Workboxのルーティングモジュールを使用してこれらをキャッシュできます。 方法は次のとおりです。
//add in src/src-sw.js workbox.routing.registerRoute( /https:\/\/api\.exchangeratesapi\.io\/latest/, new workbox.strategies.NetworkFirst({ cacheName: "currencies", plugins: [ new workbox.expiration.Plugin({ maxAgeSeconds: 10 * 60 // 10 minutes }) ] }) );
これにより、URLhttps https://api.exchangeratesapi.io/latest
に一致するリクエストURLの動的キャッシュが設定されます。
ここで使用したキャッシング戦略はNetworkFirst
と呼ばれます。 よく使用されるものは他に2つあります。
-
CacheFirst
-
StaleWhileRevalidate
CacheFirst
は、最初にキャッシュ内でそれを探します。 見つからない場合は、ネットワークから取得します。 StaleWhileRevalidate
は、ネットワークとキャッシュに同時に移動します。 キャッシュの応答をページに返します(バックグラウンドで)。新しいネットワーク応答を使用して、次に使用されるときにキャッシュを更新します。
私たちのユースケースでは、頻繁に変化する為替レートを扱っているため、 NetworkFirst
を使用する必要がありました。 ただし、ユーザーがオフラインになった場合、少なくとも10分前のレートを表示できます。そのため、 maxAgeSeconds
を10 * 60
秒に設定して有効期限プラグインを使用しました。
アプリの更新を管理する
ユーザーがページをロードするたびに、Service Workerが既にインストールされて実行されている場合でも、ブラウザーはnavigator.serviceWorker.register
コードを実行します。 これにより、ブラウザは新しいバージョンのServiceWorkerがあるかどうかを検出できます。 ブラウザは、ファイルが変更されていないことに気付くと、登録呼び出しをスキップします。 そのファイルが変更されると、ブラウザは新しいバージョンのService Workerがあることを認識し、現在実行中のServiceWorkerと並行して新しいServiceWorkerをインストールします。
ただし、同時にアクティブ化できるService Workerは1つだけであるため、 installed/waiting
フェーズで一時停止します。
以前のServiceWorkerによって制御されていたすべてのブラウザーウィンドウが閉じられた場合にのみ、新しいServiceWorkerが安全にアクティブ化されます。
また、 skipWaiting()
(または、 self
はサービスワーカーのグローバル実行コンテキストであるため、 self.skipWaiting()
))を呼び出すことにより、手動で制御することもできます。 ただし、ほとんどの場合、最新の更新を取得するかどうかをユーザーに尋ねた後でのみ、これを行う必要があります。
ありがたいことに、 workbox-window
はこれを達成するのに役立ちます。 これは、Workbox v4で導入された新しいウィンドウライブラリであり、ウィンドウ側の一般的なタスクを簡素化することを目的としています。
次のようにインストールすることから始めましょう。
npm install workbox-window
次に、ファイルindex.jsの先頭にあるWorkbox
をインポートします。
import { Workbox } from "workbox-window";
次に、登録コードを以下に置き換えます。
if ("serviceWorker" in navigator) { window.addEventListener("load", () => { const wb = new Workbox("/sw.js"); wb.register(); }); }
次に、IDを持つ更新ボタンを見つけますworkbox-waiting
イベントをリッスンします。
//add before the wb.register() const updateButton = document.querySelector("#app-update"); // Fires when the registered service worker has installed but is waiting to activate. wb.addEventListener("waiting", event => { updateButton.classList.add("show"); updateButton.addEventListener("click", () => { // Set up a listener that will reload the page as soon as the previously waiting service worker has taken control. wb.addEventListener("controlling", event => { window.location.reload(); }); // Send a message telling the service worker to skip waiting. // This will trigger the `controlling` event handler above. wb.messageSW({ type: "SKIP_WAITING" }); }); });
このコードは、新しい更新がある場合(つまり、Service Workerが待機状態の場合)に更新ボタンを表示し、 SKIP_WAITING
メッセージをServiceWorkerに送信します。
service Workerファイルを更新し、 skipWaiting
を呼び出すようにSKIP_WAITING
イベントを処理する必要があります。
//add in src-sw.js addEventListener("message", event => { if (event.data && event.data.type === "SKIP_WAITING") { skipWaiting(); });
次に、 npm run dev
を実行してから、ページをリロードします。 コードに移動し、ナビゲーションバーのタイトルを「Navbarv2」に更新します。 ページを再度リロードすると、更新アイコンが表示されるはずです。
まとめ
現在、当社のWebサイトはオフラインで機能し、ユーザーに新しい更新について通知することができます。 ただし、PWAを構築する際の最も重要な要素は、ユーザーエクスペリエンスであることに注意してください。 ユーザーが使いやすいエクスペリエンスの構築に常に焦点を合わせます。 私たちは開発者として、テクノロジーに興奮しすぎて、ユーザーのことを忘れてしまう傾向があります。
これをさらに一歩進めたい場合は、ユーザーがサイトをホーム画面に追加できるようにするWebアプリマニフェストを追加できます。 また、Workboxについて詳しく知りたい場合は、WorkboxのWebサイトで公式ドキュメントを見つけることができます。
SmashingMagの詳細:
- モバイルアプリまたはPWAでより多くのお金を稼ぐことができますか?
- プログレッシブWebアプリケーションの広範なガイド
- ネイティブとPWA:挑戦者ではなく、選択肢!
- Angular6を使用したPWAの構築