Chrome拡張のメッセージに Map や BigInt を渡したら、受信側で形が変わってしまった。こういう経験はありませんか。
Chromeの拡張間メッセージは、これまでJSON相当の直列化でした。Chrome 148からは、Manifestに1行足すだけでStructured Cloneを選べます。
まずJSON直列化で送ってみます
従来の拡張メッセージは、JSONで表現できるデータを送る前提です。
const values = new Map([['id', 123]]);
chrome.runtime.sendMessage(values);
このままだと、受信側でMapとして使えるとは限りません。JSONではMapやSet、BigInt、Date、Errorなどをそのまま表現できないためです。Mapを配列へ変換して送るような手作業が必要になります。
Structured Cloneを選ぶ
では、Manifestに設定を追加してみましょう。
{
"manifest_version": 3,
"name": "Example Extension",
"version": "1.0.0",
"message_serialization": "structured_clone"
}
これで拡張内のメッセージ通信にStructured Cloneを使えるようになります。Mapなら、送信側で作ったMapが受信側でもMapとして届きます。
// sender.js
const values = new Map([['id', 123]]);
chrome.runtime.sendMessage(values);
// service-worker.js
chrome.runtime.onMessage.addListener((message) => {
console.log(message.get('id')); // 123
});
JSON用の変換コードを減らせるので、データの型を保ったまま受け渡したい拡張では便利です。Chromeの公式例では、FileやBlobも対応例として挙げられています。
切り替える前に確認すること
この設定は互換性のためにオプトインです。設定を省略した場合やChrome 148未満では、従来のJSON方式が使われます。
拡張機能同士で通信する場合は、両方の直列化形式を合わせてください。片方がJSON、もう片方がStructured Cloneだと、メッセージ送信に失敗してポートが閉じることがあります。
また、SharedArrayBufferは対応していません。ArrayBufferなどの転送可能オブジェクトも、転送ではなくコピーになります。さらに、Structured Cloneはオブジェクトの toJSON() を呼びません。
class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
toJSON() {
return { name: this.name };
}
}
JSON方式ならパスワードを取り除けても、Structured Cloneではプロパティがそのままコピーされます。秘密情報を隠す目的で toJSON() に頼っているコードは、そのまま切り替えないでください。
既存の拡張はすぐに切り替えなくて大丈夫
ChromeはJSON方式を廃止するわけではありません。既存の拡張で、メッセージを普通のオブジェクトと文字列だけに限定できているなら、急いでManifestを変更する必要はないと思います。
逆に、MapやSetを毎回配列へ変換している、FileやBlobを扱っているという場合は、Structured Cloneを試す価値があります。まずは送受信するデータを洗い出し、Chrome 148以上のテスト環境で確認してみてください。
Chrome拡張のメッセージ通信は、便利だからといって形式を変えれば終わりではありません。受信側の型、拡張同士の互換性、toJSON() によるマスキングの有無まで確認してから切り替えるのが安全です。
詳しい仕様はChrome公式ブログのStructured Clone解説とChrome ExtensionsのWhat’s Newで確認できます。


コメント