これは FOSS4G Advent Calendar 2025 の三日目の記事です。
初日は@frogcatさんによる、国土地理院の 標高タイル から様々な地図表現を生成する ServiceWorker、dempng-worker がレポートされました。
おお、Web地図でも ServiceWorker が話題に。
ServiceWorker は私も、Weiwudi で使っている技術です。
私自身過去、こんなに多彩な機能じゃなくて、標高 => 等高線の生成機能だけを Service Worker 化しようとして、等高線側処理がよくわからなくて挫折しましたが、それ以上の多彩な機能付きで形にしきるあたり、@frogcatさんさすがです。
しかし、FacebookのFOSS4G系友人などの間で、ServiceWorkerって何?みたいな疑問を挙げている人を見たので、ServiceWorkerとは何か、Web地図とどのように親和性があるか、ということを少し説明する記事を書こうと思いました。
そもそもService Workerとは何か
ServiceWorkerは、一言でいうと、ブラウザの中で動く「イベント駆動のバックグラウンドワーカー」 です。
- JavaScript ファイルとしてページに登録される(
service-worker.jsみたいな感じ) - ページとは別スレッドで動く(ServiceWorkerからDOMには触れない)
-
install/activate/fetch/pushなどのイベントを受け取って処理する - オリジン+パスごとの「スコープ」を持ち、その範囲のリクエストを横取りできる
- HTTPS(と localhost)でしか動かない
特に重要なのは fetch イベントで、これにロジックを実装することで、
- リクエストをそのままネットワークに流す
- 事前にキャッシュしておいたレスポンスを返す
- あるいは両方を組み合わせて返す
- レスポンスやキャッシュを加工して、別コンテンツにして返す
といった「ブラウザ内プロキシ」のようなことができます。
ServiceWorkerを使わないと、
- すべてのリクエストはブラウザ -> サーバーに直接飛ぶ
- オフライン時はそもそも何もできない
- キャッシュもブラウザ任せ
しかできない状態だったのが、ServiceWorkerを挟むことで、
- 「自分で書いたロジック」でキャッシュ戦略や変換処理を組める
- オフラインでもとりあえず画面を出せる
- サーバからのプッシュ通知や、バックグラウンド同期も扱える
といった、およそこれまでのWebサイトではできなかったようなことが可能になります。
dempng-workerを例にServiceWorkerの説明
ここでdempng-workerの動作を、ServiceWorkerを使うとき使わないときを比較しつつ説明しましょう。
まず地図APIでタイル表現を変える場合、地図APIのタイルロード機能でオリジナルのタイルを読み込み後、各地図API独自のプラグイン機構を用いて表現の変換ロジックを実装し、それを用いて表現を変更、表示する形となります。
しかし、この仕組みだと、LeafletやOpenLayers、MapLibre GL JSといった地図APIごとに、異なる仕組みで実装する必要があります。
これだと、プラグインがない地図APIでは、表現の変更を実現できません。
そこで、表現の変更を地図APIの外に出せば、地図APIに関係なく、表現の変更ができるということになります。
このような仕組みを実現するのに、長らく一般的だった方法は、間に変換サーバを挟む構造でしょう。
この仕組みだと、地図APIは表現変更済みのタイルを読み込むだけなので、地図APIのI/Fの違いと無関係に、表現の変更を実現できます。
サーバから表現変更済みのタイルが送られてくるので、ブラウザの地図APIだけでなく、QGIS等でも利用できます。
一方で、サーバが必要となり管理運用しなければならなくなるのが、この構成の弱点と言えます。
標高タイルではなくベクタタイルのレンダリングという処理の違いはありますが、レンダリング済みタイルを配信する、chiitilerのようなタイルサーバも、この構成の事例かと思います。
それに対し、dempng-workerのようなServiceWorkerを用いた構成の場合、以下のような形になります。
この仕組みだと、以前の一般的な構成ではサーバ側で行われていた変換ロジックが、ブラウザのDOMが動作するメインスレッドとは別の、ワーカースレッドという背後で動くServiceWorkerの中で行われるので、サーバは不要で、かつ地図API横断で地図表現の変更を実現できます。
しかし一方で、これはモダンブラウザに実装されているワーカースレッド/ServiceWorkerという仕組みを用いているので、それを持たないQGISなどで、この表現変更されたタイルを利用することはできません。
その意味で、このような処理をサーバーサイドでやるか、ブラウザのワーカースレッドでやるかは一長一短ですが、いずれにせよ「一長一短の片方の選択肢を可能にする技術」が、ServiceWorkerになります。
Web地図 × ServiceWorkerの親和性
ServiceWorkerは表現の変更だけでなく、様々な処理をさせることができます。
私が作成したWeiwudiのような、キャッシュ管理にも使えます。
Webブラウザは、HTMLを表示する仕組みの実装であり、ChromeやEdge、Firefoxなど様々な実装がありますが、HTMLやJavaScriptを解釈する仕様は共通に定義されており、Webアプリが各ブラウザで大きな動作差をすることはありません。
しかし、Leaflet、OpenLayers、MapLibre GL JS、Mapbox、Google、HEREと多数あるWeb地図APIは、地図データにとってのブラウザのようなものだと思いますが、データの方の仕様はあるものの、一旦表現を行った後の、動作を調整するための仕組みの共通仕様がありません。
データを受け取って、表現を変えたり動作を変えたりしようと思うと、各APIそれぞれのAPI仕様やプラグイン仕様に基づいて実装する必要があります。
しかし、ServiceWorkerを使えば、動作の変化を地図APIの実装差の外に出し、共通動作がかなり保証されているブラウザ実装のレイヤーに、しかもクライアントサイドで追いやることができます。
もちろん、地図のインタラクティブな動作の実現に必要な差を吸収することはできませんが、少なくともデータの管理で実現できる動作差については、実装を地図APIの外に追いやれます。
またHTMLウェブサイトは、ページネーションなどの特殊な処理がない限り、とりあえずは一度静的に表示されたページリソースがあれば、PWA (Progressive Web Application) などでオフライン時などに表示するためのキャッシュ範囲を管理するにも、ブラウザがキャッシュ対象の範囲を判定するのも簡単です。
しかし、Web地図はそうもいきません。
ページネーションも同様ですが、地図APIが大阪駅前を表示中にリソースキャッシュされたからと言って、オフライン表示時に福島駅までスクロールしたらタイルがキャッシュされておらず表示されない、ということもあり得ますが、ServiceWorkerを用いれば、範囲を指定してのキャッシュ獲得/削除を、地図API横断で簡単に実現できます。
もちろん、ServiceWorkerを用いずに各API上で実装することも、IndexedDBはメインスレッドからでも触れますから、実現は可能ですが、各APIで異なる実装になってしまいます。
このように、今現在Web地図が持つ様々な実装上の課題、地図APIごとに動作を変更させる仕様が揃っていない問題、オフライン動作などのためにキャッシュなどの範囲を制御しにくい問題などを、ServiceWorkerはある程度解消することができます。
それも、サーバの力を借りずに。
なぜ、Web地図界隈でこれまでServiceWorkerが流行らなかったのかよくわからなかったのですが、本当にWeb地図とは親和性の高い技術だと思うので、ぜひ注目してほしいです。



