Mainline は、ファッション業界の最大のデザイナー ブランド名を扱うオンライン衣料品小売業者です。英国を拠点とするこの企業は、主要なパートナーと戦略的に連携している社内エキスパートのチームに、すべてのユーザーにスムーズなショッピング体験を提供することを任せています。7 つのカスタム ビルドされた地域別ウェブサイトとアプリを通じて 100 を超える国に市場展開している Mainline は、e コマース サービスを競合他社と競い合えるようにし続けます。
課題
Mainline Menswear の目標は、モバイル向けに最適化された現在のウェブサイトを、モバイルファーストのビジョンに沿ったプログレッシブな機能で補完し、スマートフォン市場の拡大を念頭に置いてモバイル対応のデザインと機能に重点を置くことでした。
解決策
その目的は、Mainline Menswear ウェブサイトの元のモバイル フレンドリー バージョンを補完する PWA を構築してリリースし、そのデータを現在 Android と iOS で利用可能なハイブリッド モバイルアプリと比較することでした。
アプリがリリースされ、Mainline Menswear の一部ユーザーが使用するようになると、PWA、アプリ、ウェブの主要な統計情報の違いを特定できるようになりました。
ウェブサイトを PWA に変換する際に Mainline が採用したアプローチは、ウェブサイト用に選択したフレームワーク(Nuxt.js、Vue.js を利用)が将来の変化に耐え、急速に変化するウェブ テクノロジーを利用できるようにすることでした。
結果
139%
PWA はウェブよりもセッションあたりのページ数が多い。
161%
PWA とウェブのセッション継続時間の差異。
10%
PWA の直帰率がウェブよりも低い
12.5%
PWA での平均注文額の伸び(ウェブとの比較)
55%
PWA のコンバージョン率がウェブよりも高い。
243%
PWA とウェブのセッションあたりの収益の差が大きい。
技術的な詳細
Mainline Menswear は、Nuxt.js フレームワークを使用して、サイトをバンドルしてレンダリングしています。これはシングルページ アプリケーション(SPA)です。
サービス ワーカー ファイルの生成
Service Worker を生成するために、Mainline Menswear は nuxt/pwa
Workbox モジュールのカスタム実装を使用して設定を追加しました。
nuxt/pwa
モジュールをフォークしたのは、標準バージョンではできなかった、または問題があった Service Worker ファイルに、カスタマイズをさらに追加できるようにするためです。そのような最適化の 1 つは、サイトのオフライン機能に関するものでした。たとえば、デフォルトのオフライン ページの表示や、オフライン中の分析情報の収集などです。
ウェブアプリ マニフェストの構造
チームは、さまざまなモバイルアプリ アイコンサイズのアイコンと、name
、description
、theme_color
などのウェブアプリの詳細を含むマニフェストを作成しました。
{
"name": "Mainline Menswear",
"short_name": "MMW",
"description": "Shop mens designer clothes with Mainline Menswear. Famous brands including Hugo Boss, Adidas, and Emporio Armani.",
"icons": [
{
"src": "/_nuxt/icons/icon_512.c2336e.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#107cbb"
}
インストールされたウェブアプリは、ブラウザを介さなくてもホーム画面から起動できます。そのためには、ウェブアプリ マニフェスト ファイルに display
パラメータを追加します。
{
"display": "standalone"
}
最後に、マニフェストの start_url
フィールドに utm_source
パラメータを追加するだけで、ホーム画面からウェブアプリにアクセスしたユーザーの数を簡単にトラッキングできるようになりました。
{
"start_url": "/?utm_source=pwa"
}
迅速なナビゲーションのためのランタイム キャッシュ
ウェブアプリのキャッシュ保存は、ページ速度の最適化とリピーター向けの優れたユーザー エクスペリエンスの提供に不可欠です。
ウェブでのキャッシングには、さまざまなアプローチがあります。チームは、HTTP キャッシュと Cache API を組み合わせて、クライアントサイドでアセットをキャッシュに保存しています。
Cache API を使用すると、Mainline Menswear はキャッシュに保存されたアセットをより細かく制御し、各ファイル形式に複雑な戦略を適用できます。どれも複雑で設定やメンテナンスが難しいように思えますが、Workbox を使用すると、そのような複雑な戦略を簡単に宣言でき、メンテナンスの負担が軽減されます。
CSS と JS のキャッシュ保存
CSS ファイルと JS ファイルについては、StaleWhileRevalidate
Workbox 戦略を使用してキャッシュに保存し、キャッシュ経由で提供することにしました。この戦略により、すべての Nuxt CSS ファイルと JS ファイルを高速で提供できるため、サイトのパフォーマンスが大幅に向上します。同時に、次回のアクセスに向けてファイルがバックグラウンドで最新バージョンに更新されます。
/* sw.js */
workbox.routing.registerRoute(
/\/_nuxt\/.*(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'css_js',
}),
'GET',
);
Google フォントのキャッシュ保存
Google Fonts のキャッシュ戦略は、次の 2 つのファイル形式によって異なります。
@font-face
宣言を含むスタイルシート。- 基になるフォント ファイル(上記のスタイルシートでリクエスト)。
// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy.
workbox.routing.registerRoute(
/https:\/\/fonts\.googleapis\.com\/*/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'google_fonts_stylesheets',
}),
'GET',
);
// Cache the underlying font files with a cache-first strategy for 1 year.
workbox.routing.registerRoute(
/https:\/\/fonts\.gstatic\.com\/*/,
new workbox.strategies.CacheFirst({
cacheName: 'google_fonts_webfonts',
plugins: [
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200],
}),
new workbox.expiration.ExpirationPlugin({
maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year
maxEntries: 30,
}),
],
}),
'GET',
);
画像のキャッシュ
画像については、Mainline Menswear は 2 つの戦略を採用することにしました。最初の戦略は、CDN から取得されるすべての画像(通常は商品画像)に適用されます。ページに画像が多いため、ユーザーのデバイスのストレージを過度に使用しないようにしています。そこで、Workbox を使用して、ExpirationPlugin
を使用してCDN からのみ取得される画像をキャッシュに保存する戦略を追加し、最大 60 個の画像をキャッシュに保存するようにしました。
リクエストされた 61 番目(最新)の画像が 1 番目(最も古い)の画像に置き換えられるため、どの時点でもキャッシュに保存される商品画像は 60 枚以下になります。
workbox.routing.registerRoute(
({ url, request }) =>
url.origin === 'https://mainline-menswear-res.cloudinary.com' &&
request.destination === 'image',
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'product_images',
plugins: [
new workbox.expiration.ExpirationPlugin({
// Only cache 60 images.
maxEntries: 60,
purgeOnQuotaError: true,
}),
],
}),
);
2 つ目のイメージ戦略は、オリジンによってリクエストされた残りの画像を処理します。これらの画像は、オリジン全体を通じて非常に少数になる傾向がありますが、念のため、キャッシュに保存される画像の数も 60 に制限されています。
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg|webp)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'images',
plugins: [
new workbox.expiration.ExpirationPlugin({
// Only cache 60 images.
maxEntries: 60,
purgeOnQuotaError: true,
}),
],
}),
);
オフライン機能を提供する
オフライン ページは、Service Worker をインストールして有効にした直後に事前キャッシュされます。そのためには、すべてのオフライン依存関係(オフライン HTML ファイルとオフライン SVG アイコン)のリストを作成する。
const OFFLINE_HTML = '/offline/offline.html';
const PRECACHE = [
{ url: OFFLINE_HTML, revision: '70f044fda3e9647a98f084763ae2c32a' },
{ url: '/offline/offline.svg', revision: 'efe016c546d7ba9f20aefc0afa9fc74a' },
];
プリキャッシュ リストは Workbox にフィードされます。Workbox は、URL をキャッシュに追加する、リビジョンの不一致を確認する、更新する、CacheFirst
戦略でプリキャッシュ ファイルを提供するといった、すべての面倒な作業を処理します。
workbox.precaching.precacheAndRoute(PRECACHE);
オフライン ナビゲーションの処理
Service Worker が有効になり、オフライン ページがプリキャッシュされると、ユーザーによるオフライン ナビゲーション リクエストに応答するために使用されます。Mainline Menswear のウェブアプリは SPA ですが、オフライン ページは、ページが再読み込みされた後、ユーザーがブラウザタブを閉じて再度開いた後、またはオフライン中にホーム画面からウェブアプリが起動された場合にのみ表示されます。
これを実現するために、Mainline Menswear は、事前キャッシュされたオフライン ページで失敗した NavigationRoute
リクエストのフォールバックを提供しています。
const htmlHandler = new workbox.strategies.NetworkOnly();
const navigationRoute = new workbox.routing.NavigationRoute(({ event }) => {
const request = event.request;
// A NavigationRoute matches navigation requests in the browser, i.e. requests for HTML
return htmlHandler.handle({ event, request }).catch(() => caches.match(OFFLINE_HTML, {
ignoreSearch: true
}));
});
workbox.routing.registerRoute(navigationRoute);
デモ
成功したインストールのレポート
ウェブアプリは、ホーム画面の起動トラッキング(ウェブ アプリケーション マニフェストで "start_url": "/?utm_source=pwa"
を使用)とは別に、window
の appinstalled
イベントをリッスンして、アプリのインストールの成功をレポートします。
window.addEventListener('appinstalled', (evt) => {
ga('send', 'event', 'Install', 'Success');
});
ウェブサイトに PWA 機能を追加すると、ショッピングの顧客体験がさらに向上し、[プラットフォーム固有の] アプリよりも市場投入までの時間を短縮できます。
Andy Hoyle、開発責任者
まとめ
プログレッシブ ウェブアプリとその作成方法について詳しくは、web.dev のプログレッシブ ウェブアプリのセクションをご覧ください。
プログレッシブ ウェブアプリのその他の事例紹介については、事例紹介のセクションをご覧ください。