23443f5
39eaa9c
23443f5
5379ab8
39eaa9c
23443f5
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
5379ab8
39eaa9c
23443f5
39eaa9c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
<!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">
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>
`;
const iframeBlob = new Blob([iframeHTML], { type: 'text/html' });
const iframeUrl = URL.createObjectURL(iframeBlob);
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>
|