Service Worker は「ブラウザの中に住む、裏方の小さなサーバー」
まずイメージからいきます。
Service Worker は、「ブラウザの中で動く、あなたのサイト専用の“裏方サーバー”」 です。
普通の JavaScript は「ページの中」で動きます。
ページを閉じたら終わりだし、そのタブの中だけが世界です。
一方、Service Worker は
ページとは別のスレッドで動く
ネットワーク通信を横取りして、自分で返事できる
キャッシュを自分で管理できる
場合によっては、ページが開いていなくても動ける(プッシュ通知など)
という、かなり特殊な存在です。
「オフラインでも動く Web アプリ」
「PWA(インストールできる Web アプリ)」
を支える中核が、この Service Worker です。
どこで動くのか:ページとは別世界の「ワーカー」
メインスレッドとは分離された環境
通常の JS は、window の中で動きますよね。
DOM を触ったり、document をいじったり。
Service Worker は、window も document もない世界 で動きます。
代わりに、
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 でもここまでできるのか」 という楽しさが一気に広がります。
