MV3 service workerからoffscreenでDOM解析

この記事は約4分で読めます。

Manifest version 3(MV3) では background が service worker に置き換えられました。service worker では DOMParser が使えません。

Chrome のバージョン 109 から offscreen を通して service worker で DOMParser が使えるようになりました。

chrome.offscreen 公式ドキュメント(英語)

offscreenを使った処理の流れ

  1. chrome.offscreen.createDocument で offscreen を開く
  2. (service worker側) chrome.runtime.sendMessage でリクエストを出す
  3. (offscreen側) chrome.runtime.onMessage で受信して処理する

DOMParser でタイトルを抽出する

以下のコードは document からタイトルを抽出する例です

manifest.json

manifest のバージョンを v3 にして permissions に offscreen を追加します。

{
  "manifest_version": 3,
  "name": "extension name",
  "permissions": [
    "offscreen"
  ],
  "background": {
    "service_worker": "/service_worker.js"
  }
}

service_worker.js

const document = ... // fetch などで取得した文字列が入っている

chrome.offscreen.createDocument({ reasons: ['DOM_PARSER'], justification: 'parse dom', url: './offscreen.html' })
  .then(() => {
    chrome.runtime.sendMessage({ action: 'getTitle', document }, (title) => {
      chrome.offscreen.closeDocument()
      console.log(title)
    })
  })

offscreen.createDocument の reasons は offscreeの寿命に関係するそうです。justification はどんな役割なのか把握できていません。

offscreen はchrome.offscreen.closeDocument() しなくても放っておけば勝手に終了します。しかし、複数の offscreen が生きていると二重に処理される(このコードでは複数回 title が表示される)可能性があります。意図しない動作を防ぐために明示的にcloseDocument()した方が良いでしょう。

offscree.html

chrome.offscreen.createDocument の url にはローカルのファイルを指定します。そのため、offscreen.js を読み込む offscreen.html を用意します。

<html><head><script src="offscreen.js"></script></head></html>

offscreen.js

メッセージを受信してDOMの解析を行います。
callback で解析した結果を返します。

chrome.runtime.onMessage.addListener((request, _sender, callback) => {
  if (request.action === 'getTitle') {
    const parser = new DOMParser()
    const document = parser.parseFromString(request.document, 'text/html')
    const title = document.head.querySelector('title')
    callback(title.innerText)
  }
})

最後に

offscreen.html を用意しないといけないところが面倒です。

chrome のメッセージングではプリミティブな値しかやり取りできないので注意してください。この例では offscreen.js から document を callback に渡しても service_worker.js では受け取れません。

コメント

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