🦔

Remix(Reactフレームワーク)にServiceWorkerを追加してPWA化する方法

2022/01/05に公開

RepitanにServiceWorkerを入れたので備忘録として残します。
NuxtのときはPWAとかほぼ自動でやってくれてたのですが、Remixの場合手動でやらないといけませんでした。

どうしてPWA化するの?

Remixはデフォルトで高速ですが、インストール可能なPWAを構築したり、アプリをオフラインで動作させたり、Remixアプリケーションの負荷を可能な限り最適化したい場合はServiceWorkerがお手軽な手段になってきます。
個人的には「ホーム画面に追加」機能と、ブラウザのメニューバーなどが非表示になってくれる点がとても気に入っています。

ServiceWorkerを追加する手順

  1. manifest.jsonを作成
public/manifest.json
{
  "name": "Repitan",
  "short_name": "Repitan",
  "icons":[
    {
      "src":"/icons/icon-72x72.png",
      "sizes":"72x72",
      "type":"image/png"
    },
    {
      "src":"/icons/icon-128x128.png",
      "sizes":"128x128",
      "type":"image/png"
    }
    ,
    {
      "src":"/icons/icon-144x144.png",
      "sizes":"144x144",
      "type":"image/png"
    },{
      "src":"/icons/icon_152.png",
      "sizes":"152x152",
      "type":"image/png"
    },{
      "src":"/icons/icon_192.png",
      "sizes":"192x192",
      "type":"image/png"
    },{
      "src":"/icons/icon_384.png",
      "sizes":"384x384",
      "type":"image/png"
    },{
      "src":"/icons/icon_512.png",
      "sizes":"512x512",
      "type":"image/png"
    }
  ],
  "theme_color": "#ffffff",
  "background_color": "#ffffff",
  "display": "standalone",
  "scope": "/",
  "start_url": "/",
  "lang": "ja"
}

上記の内容は最低限なものになるので、その他にも色々設定したい場合はMDNのウェブアプリマニフェストを参考にすると良さそうです

  1. manifest.jsonを読み込む
app/root.tsx
import {
  Links
} from "remix";

export const links = () => {
  return [
    { rel: "manifest", href: '/manifest.json' },
  ]
}
  1. sw.jsを作成
public/sw.js
self.addEventListener("fetch", (event) => {
  let url = new URL(event.request.url);
  let method = event.request.method;

  if (method.toLowerCase() !== "get") return;

  if (
    url.pathname.startsWith("/images/") ||
    url.pathname.startsWith("/json/") ||
    url.pathname.startsWith("/styles/")
  ) {
    event.respondWith(
      caches.open("assets").then(async (cache) => {
        let cacheResponse = await cache.match(event.request);
        if (cacheResponse) return cacheResponse;
        let fetchResponse = await fetch(event.request);
        cache.put(event.request, fetchResponse.clone());
        return fetchResponse;
      })
    );
  }
  return;
});
  1. entry.client.tsxにsw.jsを読み込ませて完了
app/entry.client.tsx
if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker.register("/sw.js");
  });
}

PWAの変化

変更前

変更後

Discussion