dev-tools / index.html
soiz1's picture
Update index.html
5379ab8 verified
raw
history blame
4.92 kB
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>1ファイル完結型 Service Worker via iframe+Blob</title>
<style>
body { font-family: sans-serif; padding: 1em; }
#log { margin-top: 1em; font-size: 14px; }
.success { color: green; margin-bottom: 1em; }
.error { color: red; margin-bottom: 1em; }
pre { background: #f9f9f9; padding: 0.5em; border: 1px solid #ccc; }
</style>
</head>
<body>
<h1>1ファイルで完結する Service Worker (iframe + Blob)</h1>
<div id="log">Service Worker の登録を試みています…</div>
<script>
// iframe内のHTMLを文字列として用意(Service Workerスクリプト含む)
const iframeHTML = `
<!DOCTYPE html>
<html>
<head><title>SW iframe</title></head>
<body>
<script type="text/javascript">
// Service Worker スクリプトを文字列で用意
const swCode = \`
self.addEventListener('fetch', event => {
const url = event.request.url;
const method = event.request.method;
event.respondWith(
fetch(event.request)
.then(response => {
const clone = response.clone();
clone.text().then(body => {
self.clients.matchAll().then(clients => {
clients.forEach(client => {
client.postMessage({
type: 'fetch-log',
url,
method,
status: response.status,
body: body.slice(0, 200)
});
});
});
});
return response;
})
.catch(error => {
self.clients.matchAll().then(clients => {
clients.forEach(client => {
client.postMessage({
type: 'fetch-error',
url,
method,
error: error.toString()
});
});
});
throw error;
})
);
});
\`;
// Blob URLとして作成
const blob = new Blob([swCode], { type: 'application/javascript' });
const swBlobUrl = URL.createObjectURL(blob);
// Service Worker 登録
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(swBlobUrl)
.then(() => {
parent.postMessage({ type: 'sw-registered' }, '*');
})
.catch(err => {
parent.postMessage({ type: 'sw-error', error: err.toString() }, '*');
});
// Service Worker からのメッセージを受け取り親に中継
navigator.serviceWorker.addEventListener('message', event => {
parent.postMessage({ type: 'sw-message', data: event.data }, '*');
});
}
<\/script>
</body>
</html>
`;
// Blob URLとして iframe のページを作る
const iframeBlob = new Blob([iframeHTML], { type: 'text/html' });
const iframeUrl = URL.createObjectURL(iframeBlob);
// iframe要素作成
const iframe = document.createElement('iframe');
iframe.src = iframeUrl;
iframe.style.display = 'none'; // 表示不要
document.body.appendChild(iframe);
// メッセージ受け取り処理
const logDiv = document.getElementById('log');
window.addEventListener('message', event => {
const data = event.data;
if (!data || !data.type) return;
if (data.type === 'sw-registered') {
logDiv.textContent = '✅ Service Worker 登録完了 (iframe 内)';
}
else if (data.type === 'sw-error') {
logDiv.textContent = '❌ Service Worker 登録失敗: ' + data.error;
}
else if (data.type === 'sw-message') {
const msg = data.data;
const div = document.createElement('div');
div.className = msg.type === 'fetch-log' ? 'success' : 'error';
if (msg.type === 'fetch-log') {
div.innerHTML = \`
✅ [\${msg.method}] \${msg.url} — \${msg.status}<br>
<pre>\${msg.body}</pre>
\`;
} else if (msg.type === 'fetch-error') {
div.innerHTML = \`
❌ [\${msg.method}] \${msg.url}<br>
エラー: \${msg.error}
\`;
}
logDiv.appendChild(div);
}
});
// 動作確認用fetchを親ページから実行
fetch('https://jsonplaceholder.typicode.com/posts/1');
fetch('https://httpstat.us/404');
</script>
</body>
</html>