uttk's site/articles/Service Worker を ESM で実装する

Service Worker を ESM で実装する

この記事について

ついこの間 Service Worker 内で ESM が使えるようになってることを知りました。

caiuse より引用 (情報は 2025/02 時点のモノ)

最近 Service Worker 触ってないし、ちょうどいい機会なので今回は Service Worker を ESM で書くための方法を紹介していこうと思います 💪

Service Worker を ESM で実装するには

ビルドを挟まなくても Service Worker を import などを使って実装できるようになったので、コード自体は普段から書いているコードをそのまま書くだけです 👇

./module.js
export const sayHello = () => {
  console.log("にゃ~ん")
}
./index.js
import { sayHello } from "./module.js";

sayHello();

そして Service Worker として登録する時に { type: 'module' } をオプションを付ければおk 👇

ESMファイルをServiceWorkerに登録する
navigator.serviceWorker.register('/worker.js', { type: 'module' });

基本的にはこれだけですが、

  • importする時に拡張子は省略しない
  • importScripts() は使えない

などの注意点があるので気を付けましょう。

パッケージを使う場合

skypackesm.shJSR に登録されているパッケージであれば、URL を指定することで import することが可能です。

例えば、Hono を esm.sh から import するには以下のようにします 👇

esm.shからHonoをimportする
import { Hono } from "https://esm.sh/[email protected]";

const app = new Hono();

// ...

TypeScript で実装する場合

TypeScript を使う場合はビルドする必要があります。
ビルドには tsc を使ってもいいですが個人的に swc を使う方が開発体験が良いので、ここでは swc を使ってビルドする方法を紹介します。

まずは以下のパッケージをインストールしておきます 👇

$> pmpm add -D @swc/cli @swc/core @swc/plugin-transform-imports

次に設定ファイルを以下のように設定します 👇

.swcrc
{
  "$schema": "https://swc.rs/schema.json",
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2022",
    "experimental": {
      "plugins": [
        [
          "@swc/plugin-transform-imports",
          {
            "^(.*?)\\.ts(x)?$": {
              "skipDefaultConversion": true,
              "transform": "{{matches.[1]}}.js"
            }
          }
        ]
      ]
    },
  },
  "minify": true
}

@swc/plugin-transform-imports.ts 拡張子でインポートした時に、ビルドファイルでは .js に変換されるように設定しています。

設定ファイルが実装できたら、以下のようにコマンドを実行すればビルドすることができます 👇

$> swc ./worker.ts -o ./worker.js

開発する時は Deno として扱うとラク

Service Worker を ESM として実行する都合上、import 部分を URL で実装したい場面があります。

URLでインポートする例
import { Hono } from "https://esm.sh/[email protected]";

この時、通常の TypeScript や JavaScript ではインポート先のパスに URL を指定できないのでエラーなどの警告が出てしまいますが、Deno であれば URL をデフォルトで使用できて型推論なども行ってくれるのでオススメです。

VSCode であれば、

Deno - Visual Studio Marketplace

Extension for Visual Studio Code - A language server client for Deno.

marketplace.visualstudio.com

をインストールして worker のファイルがあるフォルダのみで有効にすると良いです 👇

./settings/vscode.json
{
  // deno として扱いたいファイルがあるフォルダーを指定する
  "deno.enablePaths": ["./src/worker"]
}

参考

Service Worker の ES モジュール

Service Worker は、importScripts() の代わりに、ES モジュールの静的インポートを使用して追加のコードを取り込むことができます。

web.dev

Service Worker のインポートを理解する

Service Worker では、importScriptsを使うことでスクリプトをインポートできる。 ES Modules (以下、ESM)を使うこともできるが、ブラウザによってはまだ対応していない。Chrome ではバージョン 91 から利用できるようになった。 この記事では、これらの機能を使って Service Worker でスクリプトをインポートする方法を見ていく。 動作確認には Next.js と Google Chrome を使っている。それぞれのバージョンは以下の通り。 Next.js 10.2.0 Google Chrome 91.0.4472.77 ユーザーが初めてページ…

numb86-tech.hatenablog.com

エディター付きのReact開発環境を ブラウザーだけで実装した話

ぜひmosya Reactで遊んでみてください! https://mosya.dev/react

speakerdeck.com

あとがき

私の印象として、 Service Worker 周りの技術はキャッシュや複雑なイベントタイミングの仕様だったりが難しくてとっつきづらい所がありましたが、ESM のおかげで若干印象が良くなった気がします。

あと、ビルドツールを使わないでも扱えると言ったんですが、実際に業務で使うならビルドツールを使って最適化した方が良いと思います。

今回で言えば swc の minify オプションを有効にするだとか、Tree Shaking とかで不要なコードを削除するとかですね。その辺りの最適化も ESM になったことでやり易くなったと思います。

はい、ここまで読んでくれてありがとうございました!
これが誰かの参考になれば幸いです。
記事に間違いなどがあれば、SNSなどで教えて頂けると嬉しいです。

それではまた 👋