JavaScript | Web API:通信・ネットワーク系 - Service Worker の概要

JavaScript JavaScript
スポンサーリンク

Service Worker は「ブラウザの中に住む、裏方の小さなサーバー」

まずイメージからいきます。
Service Worker は、「ブラウザの中で動く、あなたのサイト専用の“裏方サーバー”」 です。

普通の JavaScript は「ページの中」で動きます。
ページを閉じたら終わりだし、そのタブの中だけが世界です。

一方、Service Worker は

ページとは別のスレッドで動く
ネットワーク通信を横取りして、自分で返事できる
キャッシュを自分で管理できる
場合によっては、ページが開いていなくても動ける(プッシュ通知など)

という、かなり特殊な存在です。

「オフラインでも動く Web アプリ」
「PWA(インストールできる Web アプリ)」
を支える中核が、この Service Worker です。


どこで動くのか:ページとは別世界の「ワーカー」

メインスレッドとは分離された環境

通常の JS は、window の中で動きますよね。
DOM を触ったり、document をいじったり。

Service Worker は、windowdocument もない世界 で動きます。

代わりに、

self(Service Worker 自身を指す)
caches(キャッシュストレージ)
fetch イベント(ネットワークリクエストを横取りできる)

などの API が使えます。

つまり、Service Worker は

画面を直接いじる人ではなく
「ネットワークとキャッシュを担当する裏方」

という役割です。

オリジンごと・スコープごとに 1 つ

Service Worker は、
オリジン(ドメイン + プロトコル + ポート)ごとに登録され、
さらに「どのパス以下を担当するか(スコープ)」を持ちます。

例えば、/sw.js/ で登録すると、
そのサイト全体のリクエストを担当できます。

/app/sw.js/app/ で登録すると、
/app/ 以下だけを担当する Service Worker になります。


何ができるのか:一番大きいのは「ネットワークを横取りできること」

fetch イベントでリクエストを捕まえる

Service Worker の一番のキモは、
「ページからのネットワークリクエストを横取りして、自分でレスポンスを返せる」 ことです。

Service Worker の中では、こんなコードが書けます。

self.addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  // ここで request を見て、どう返すか決める
  const cache = await caches.open("my-cache");
  const cached = await cache.match(request);

  if (cached) {
    return cached; // キャッシュがあればそれを返す
  }

  const response = await fetch(request); // ネットワークに行く
  cache.put(request, response.clone());  // キャッシュに保存
  return response;
}
JavaScript

これで、

一度取ってきたリソースをキャッシュに保存
次回以降はキャッシュから返す
ネットワークがオフラインでも、キャッシュがあれば動く

という「オフライン対応」が実現できます。

オフラインでもページを表示できる

例えば、最初のアクセス時に

HTML
CSS
JavaScript
画像

などをまとめてキャッシュしておけば、
次回以降はネットワークがなくても、
Service Worker がキャッシュからそれらを返してくれます。

これが「オフラインでも開ける Web アプリ」の正体です。


登録の流れ:ページ側と Service Worker 側の役割分担

ページ側:Service Worker を登録する

Service Worker は、ページ側から「登録」してあげる必要があります。

if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/sw.js")
      .then((registration) => {
        console.log("Service Worker registered:", registration.scope);
      })
      .catch((error) => {
        console.error("Service Worker registration failed:", error);
      });
  });
}
JavaScript

ここでやっていることは、

ブラウザが Service Worker に対応しているか確認
ページのロード後に /sw.js を登録

という流れです。

/sw.js が、実際に裏方として動く Service Worker の本体です。

Service Worker 側:インストールとアクティベート

sw.js の中では、
ライフサイクルイベントを扱います。

self.addEventListener("install", (event) => {
  console.log("Service Worker: install");
  // 初回インストール時にキャッシュしておきたいファイルを保存したりする
});

self.addEventListener("activate", (event) => {
  console.log("Service Worker: activate");
  // 古いキャッシュを消したりする
});
JavaScript

ざっくり言うと、

install
「初めて入るとき」
ここで必要なファイルをキャッシュしておくことが多い。

activate
「有効化されたとき」
古いバージョンの Service Worker やキャッシュを整理する。

という役割です。


具体例:シンプルな「オフライン対応」Service Worker

sw.js のイメージ

const CACHE_NAME = "my-app-v1";
const ASSETS = [
  "/",            // ルート
  "/index.html",
  "/styles.css",
  "/main.js",
  "/logo.png",
];

self.addEventListener("install", (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(ASSETS);
    })
  );
});

self.addEventListener("activate", (event) => {
  event.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys
          .filter((key) => key !== CACHE_NAME)
          .map((key) => caches.delete(key))
      )
    )
  );
});

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      if (cached) {
        return cached;
      }
      return fetch(event.request);
    })
  );
});
JavaScript

この Service Worker は、

インストール時に必要なファイルをまとめてキャッシュ
古いキャッシュはバージョン違いとして削除
リクエストが来たら、まずキャッシュを探し、なければネットワークへ

という、とても典型的なパターンです。

これだけで、

一度アクセスしたあとなら、
オフラインでも /index.html/main.js が返せるようになります。


重要な制約と前提

HTTPS でしか動かない(基本)

Service Worker は、
セキュリティ的にかなり強い権限 を持っています。

ネットワークを横取りできる
キャッシュを自由にいじれる

そのため、
原則として HTTPS 上でしか有効になりません
(例外として localhost は OK)

開発中は http://localhost:3000 などで試せますが、
本番環境では必ず HTTPS が必要です。

一度登録されると「しばらく居座る」

Service Worker は、一度登録されると、
ページを閉じてもすぐには消えません。

ブラウザが適切なタイミングで停止・再起動しながら、
裏方として動き続けます。

そのため、

バグった Service Worker をデプロイすると、
ユーザーのブラウザに「壊れた裏方」が残り続ける

という怖さがあります。

だからこそ、

バージョン管理(CACHE_NAME にバージョンを入れるなど)
古いキャッシュの削除
更新時の挙動(いつ新しい SW に切り替えるか)

を慎重に設計する必要があります。


初心者として Service Worker で本当に掴んでほしいこと

Service Worker は「ブラウザの中にいる、ネットワークとキャッシュ担当の裏方」
ページとは別スレッドで動き、DOM は触れないが、リクエストを横取りできる
install / activate / fetch というライフサイクルイベントが基本
キャッシュ API と組み合わせることで「オフライン対応」や「高速な再訪問」が実現できる
HTTPS が必須で、一度登録されるとしばらく居座るので、設計とバージョン管理が重要

もし次の一歩を踏みたいなら、

今の小さな静的サイトに、
「とりあえずオフラインでもトップページだけ開ける Service Worker」
を自分で書いてみるのがおすすめです。

最初は「なんか難しそうな黒魔術」に見えるかもしれないけれど、
一度「ネットワークを自分でコントロールできる感覚」を掴むと、
「Web でもここまでできるのか」 という楽しさが一気に広がります。

タイトルとURLをコピーしました