🧊

Workboxで画像をランタイムでキャッシュする

アクセスするとメガ単位でたくさんの画像を読み込むサービスがありまして・・。

リファクタによって、動的に必要な画像だけを読み込むように改修はしたけど、それでも回遊するとサイズがすごいことになる。

これをなんとかするならServiceWorkerしかない!というわけで。

Workbox

最初は0から手書きしようかと思ったけど、ちょっとやり始めただけであれこれ面倒なことがわかったので、先人に頼ることにした。

Workbox  |  Google Developers

ご丁寧に、こういうことがやりたいんじゃろ?っていうのがガイドの中にあって、そうそうこれこれ〜って感じだった。

事前キャッシュではなく、あくまでランタイムでのキャッシュがしたかったので、これ。

import { CacheableResponsePlugin } from "workbox-cacheable-response";
import { CacheFirst } from "workbox-strategies";
import { ExpirationPlugin } from "workbox-expiration";
import { registerRoute } from "workbox-routing";

registerRoute(
  ({ request }) => request.destination === "image",
  new CacheFirst({
    cacheName: "images",
    plugins: [
      new CacheableResponsePlugin({
        statuses: [0, 200],
      }),
      new ExpirationPlugin({
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
        purgeOnQuotaError: true,
      }),
    ],
  }),
);

拡張子問わず、画像に対するリクエストをキャッシュする設定。

  • ちゃんとステータスコード200で取得できたものだけ
  • キャッシュできる容量を超えたら自動パージ

というコードがこれだけで書ける。

我々が欲しかったのはServiceWorkerではなく、Workboxだったのじゃよ・・。

Rollupでプラグインなしでビルド

Workboxの使い方を探すと、PWA用途にプラグインで事前キャッシュ仕込めて簡単☆みたいなのばっか出てくる。

まぁ普通にアプリのコードと同じようにRollupで設定書いて、ビルドすればいいだけなので、特筆すべきことはない・・と思ったら、ちょっとハマった。

最終的な`rollup.config.js`はこんな感じ。

const production = process.env.NODE_ENV === "production";

export default {
  input: "src/sw.js",
  output: {
    format: "iife",
    name: "sw",
    file: "service-worker.js"
  },
  plugins: [
    resolve(),
    replace({
      "process.env.NODE_ENV": production ? "'production'" : "''",
    }),
    production && terser()
  ],
}

まず最初の注意点は、`format: iife`にするところ。

次に、`process.env`にアクセスするコードがWorkbox側にあるので、それを処理しないと`process is not defined`って`register()`時にエラーになるところ・・。
(そんなコードを公開するんじゃないよという気持ち)

あとは使ってるモジュールたちをいつもどおり`npm install`すれば、ビルドできる。

GitHub Pagesの場合

専用のドメインでやってるなら特に引っかかりはしないはず。

けど、そのままのGitHub Pagesの場合、ユーザー名がドメインになってたり、末尾スラッシュの制御ができなかったりする。

それを回避するためにこう書けばいいよという神ガイドがこちらのGistにあった。

ServiceWorker for github pages.

最初`scope`のパスのことに気付かずなんで動かんのや・・ってハマってたので助かった〜。