1. Hugoで構築したサイトをPWA化

1-1. PWAとは
  • PWAとは、「Progressive Web Apps」の略称で、モバイル向けWebサイトをスマートフォン向けアプリのように使えるようにする仕組みです。 PWAはそれ自体が何か特殊な一つの技術、というわけではありません。レスポンシブデザイン、HTTPS化など、Googleが定める要素を備えたWebサイトであり、オフラインやプッシュ通知に対応するためのブラウザAPI(Service Workerなど)を利用しているWebサイトをPWAと呼びます。
  • Web アプリ マニフェストを追加する方法
  • 本サイトでは、トップページのみPWA化となります。
1-2. 手順
  1. manifest.webmanifestの作成

  2. icon画像の作成

  3. icon画像の配置

  4. manifest.webmanifestの修正と配置

  5. ブラウザでmanifest.webmanifestの内容が表示されていることを確認

  6. Service Workeの作成

  7. Service Workeの配置と確認

1-3. manifest.webmanifestの作成
  • Simi Cartのサイトは、PWA マニフェスト ジェネレーターとして「Web アプリ マニフェスト」と、PWA 用にサイズが最適化されたアイコンを自動的に生成してくれます。

  • display:standaloneとしました。 Web アプリを開いて、スタンドアロン アプリのようなルック アンド フィールにします。アプリは、ブラウザーとは別の独自のウィンドウで実行され、URL バーなどの標準のブラウザー UI 要素を非表示にします。

  • scope:ブラウザーがアプリ内にあると見なす URL のセットを定義し、ユーザーがいつアプリを離れたかを判断するために使用されます。scopeは、Web アプリのすべてのエントリ ポイントと出口ポイントを包含する URL 構造を制御します。scope,scope,start_url,scope内に存在している必要があります。

    • scope が相対 URL である場合、ベース URL はマニフェストの URL になります。

    • スコープは、ナビゲーションを現在のサイトに制限します。

"scope": "https://example.com/"
  • ナビゲーションを現在のサイトのサブディレクトリーに制限します。
"scope": "https://example.com/subdirectory/"

1-4. Service Worker
// Incrementing OFFLINE_VERSION will kick off the install event and force
// previously cached resources to be updated from the network.
const OFFLINE_VERSION = 1;
const CACHE_NAME = 'offline';
// Customize this with a different URL if needed.
const OFFLINE_URL = 'offline.html';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(CACHE_NAME);
    // Setting {cache: 'reload'} in the new request will ensure that the response
    // isn't fulfilled from the HTTP cache; i.e., it will be from the network.
    await cache.add(new Request(OFFLINE_URL, {cache: 'reload'}));
  })());
});

self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    // Enable navigation preload if it's supported.
    // See https://developers.google.com/web/updates/2017/02/navigation-preload
    if ('navigationPreload' in self.registration) {
      await self.registration.navigationPreload.enable();
    }
  })());

  // Tell the active service worker to take control of the page immediately.
  self.clients.claim();
});

self.addEventListener('fetch', (event) => {
  // We only want to call event.respondWith() if this is a navigation request
  // for an HTML page.
  if (event.request.mode === 'navigate') {
    event.respondWith((async () => {
      try {
        // First, try to use the navigation preload response if it's supported.
        const preloadResponse = await event.preloadResponse;
        if (preloadResponse) {
          return preloadResponse;
        }

        const networkResponse = await fetch(event.request);
        return networkResponse;
      } catch (error) {
        // catch is only triggered if an exception is thrown, which is likely
        // due to a network error.
        // If fetch() returns a valid HTTP response with a response code in
        // the 4xx or 5xx range, the catch() will NOT be called.
        console.log('Fetch failed; returning offline page instead.', error);

        const cache = await caches.open(CACHE_NAME);
        const cachedResponse = await cache.match(OFFLINE_URL);
        return cachedResponse;
      }
    })());
  }

  // If our if() condition is false, then this fetch handler won't intercept the
  // request. If there are any other fetch handlers registered, they will get a
  // chance to call event.respondWith(). If no fetch handlers call
  // event.respondWith(), the request will be handled by the browser as if there
  // were no service worker involvement.
});

2. 本番環境でデプロイ


(参考サイト)

以上