以前どこかで作ったのを ESModules 対応で新しく作り直した
バックグラウンド側で行うので CORS 無視かつ https から http の fetch ができる
ページ内に JavaScript を埋め込む content_script で使うのが主な用途
fetch の API と完全な互換性はなし
export const remoteFetch = (url, type, option) => {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({ url, type, option }, res => {
if (res) {
if (res.error) {
reject(new Error(res.error))
return
}
if (res.result) {
if (type === "buffer") {
resolve(Uint8Array.from(res.result).buffer)
} else {
resolve(res.result)
}
return
}
} else {
reject("Something went wrong.")
}
})
})
}
const remoteFetchListener = (req, sender, sendResponse) => {
if (!req.url) {
sendError("missing url")
return false
}
try {
new URL(req.url)
} catch {
sendError("Invalid URL: " + req.url)
return false
}
fetch(req.url, req.option)
.then(async res => {
if (!res.ok) {
throw new Error("Rensponse is not ok: " + res.status)
}
let result = null
if (req.type === "json") {
result = await res.json()
} else if (req.type === "buffer") {
const ab = await res.arrayBuffer()
result = Array.from(new Uint8Array(ab))
} else {
result = await res.text()
}
sendResponse({ result })
})
.catch(err => {
sendError("Fetch error: " + err.message)
})
return true
function sendError(message) {
sendResponse({ error: message })
}
}
export const listenRemoteFetch = () => {
chrome.runtime.onMessage.addListener(remoteFetchListener)
}
export const unlistenRemoteFetch = () => {
chrome.runtime.onMessage.removeListener(remoteFetchListener)
}
content_script 側では remoteFetch をインポートして使う
2 つ目の引数に text, json, buffer のどれかを指定する
import { remoteFetch } from "./remoteFetch.js"
remoteFetch(url, "text").then(console.log)
バックグラウンド側では listenRemoteFetch を実行しておく
import { listenRemoteFetch } from "./remoteFetch.js"
listenRemoteFetch()
作ったはいいけど このまま使う機会は少なそう
1 ファイルにまとめてるけど 使う側で実行する関数も別で共通処理もないから ロードする量減らすならファイル分けたほうが良いかもだし
拡張機能で Modules のロードは不便なところもあるから直接スクリプトに埋め込んだり バンドルしたほうが良さそう