-
Notifications
You must be signed in to change notification settings - Fork 302
Host site URL without index.html
is intercepted by service worker
#24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
That might be related to what I reported in #1. |
I forgot to mention, I'm seeing this issue on Firefox. It seems specifying the static HTML file in the URL is consistently more reliable than without it. I'm guessing it's because the service worker skips the former URL, but intercepts the latter request since it doesn't have a file extension. (In my case it's using NGINX's That might be something to test for in #1, if the issue on Chrome still happens when visiting As for a possible solution, I wonder if the service worker can recognize whether a fetch request is coming from inside an iframe, or from visiting the host site itself (in which case it should be bypassed completely, I'm assuming). |
The culprit is the service worker as you have found. Somewhere here it decides to serve the root domain request: In the short term, we could improve the path matching. In the longer term, that will only lead to more corner cases. I like your idea much more:
I wonder if iframe sandboxing could somehow help here. If not, perhaps it's possible to attach something unique to each request intended to go to WordPress, e.g. a cookie or a header. It would also help solve #9 |
This StackOverflow answer offers some inspiration: The service worker has access to |
I explored the technique described in the StackOverflow link, and was able to make the service worker recognize if a fetch request is coming from the host window or an iframe. However, long story short, I couldn't solve the original issue due to a kind of tautological loop: when the service worker wrongly intercepts a request to the host site, at that point nothing is loaded yet - so it's impossible for the worker to get the host window's client ID. At least that's what I think is happening. I'll describe my attempt below, maybe some of it is still useful. In the host window, the app calls the service worker when it's ready. In async function init() {
const registration = await serviceWorkerReady;
// Send message to get host window client ID
registration.active.postMessage({ code: 'get-client-id' });
...
} In the service worker, the event callback gets the host's client ID. It was tricky to achieve, because the worker's In /**
* Get host window's client ID to distinguish fetch requests from inside iframe
*/
let windowClientId
const windowClientReady = new Promise((resolve, reject) => {
self.addEventListener('message', async (event) => {
if (event.data.code !== 'get-client-id') return;
const clients = await self.clients.matchAll();
for (const client of clients) {
if (client.frameType !== 'top-level') continue;
windowClientId = client.id;
resolve();
console.log( `[ServiceWorker] Got host window client ID: ${ windowClientId }` );
break;
}
});
}); The self.addEventListener( 'fetch', async ( event ) => {
const url = new URL( event.request.url );
if (!windowClientId) await windowClientReady;
// Don't process main window resources
if (event.clientId === windowClientId) {
console.log( `[ServiceWorker] Ignoring host window request: ${ url.pathname }` );
return event.respondWith( fetch(event.request) );
}
...
}); Here's where I ran into the Catch-22 situation. When a user visits the host site URL without Perhaps another way to solve this: instead of host window, to get the iframe's client ID and only intercept |
This is gold, thank you for these great explorations @eliot-akira!
I would assume WordPress isn't running when there is no |
This is a tough nut to crack, I'm still trying different angles. The specific situation I haven't been able to solve yet, is distingushing between when the browser fetches the route I've observed that sometimes the fetch event has no client ID, which makes it impossible to recognize where it's coming from. I read through the MDN docs, especially about At this point, my thinking is to not depend on event client ID since it's unreliable as far as I can tell. I'm trying a more manual way, by establishing a hand-shake exchange between host app and service worker (and after that the app sets iframe src), so the worker can know which fetch events are coming from the iframe. |
@eliot-akira This is a tough one indeed! I propose we bale out of resolving this entirely and just don't the main HTML
The wordpress.html file could have an "iframe mode" where WP would be rendered in an iframe, and a "standalone mode" where it would only register the service worker and redirect to Why? Because resolving this with My perfect flowchart for resolving the root URL
However, the implementation quickly gets unwieldy:
Either way it's more code branches to maintain and more opportunities for a mistake. |
…n the `/` route is requested Before this PR, requesting `/` could mean two different things: * Display index.html, or * Display WordPress's index.php Deciding which option is correct is hard. This commit removes the need to decide. Solves #24
…n the `/` route is requested Before this PR, requesting `/` could mean two different things: * Display index.html, or * Display WordPress's index.php Deciding which option is correct is hard. This commit removes the need to decide. Solves #24
…n the `/` route is requested Before this PR, requesting `/` could mean two different things: * Display index.html, or * Display WordPress's index.php Deciding which option is correct is hard. This commit removes the need to decide. Solves #24
…n the `/` route is requested Before this PR, requesting `/` could mean two different things: * Display index.html, or * Display WordPress's index.php Deciding which option is correct is hard. This commit removes the need to decide. Solves #24
I just renamed index.html to wordpress.html in e1235f8 I'm marking this as resolved for now, but I'm happy to reopen if you think it requires more thought @eliot-akira . |
Actually, I just realized there can be no standalone mode where the user navigates to |
Thank you for looking into this question - I think changing the file name from If I wanted, I could redirect from a simpler demo site URL to append the HTML file name. But it does "break the illusion" a little, showing the static file's existence outside the WP site's permalinks. Ideally I'd love it to be seamless, like running the original. In any case, it was a good learning experience for me to dig into this issue, to understand better how the service worker works, how the fetch event handles requests, how to communicate between host and worker process, etc. It still feels surprising and magical, seeing the whole WordPress stack running in the browser. I'm looking forward to what creative ideas it makes possible, like interactive plugin documentation and tutorials. |
Uh oh!
There was an error while loading. Please reload this page.
When deploying a demo site, I noticed it works fine when I visit the static file specifically, like
example.com/index.html
, but it has some unpredictable behavior with the root domain only, likeexample.com
. Sometimes it takes a long time to load, or doesn't load at all.I tracked down the cause (I think) to the service worker intercepting the visit to the host site and serving the WordPress site via the web worker, outside/without the iframe.
I'm still wrapping my head around how all of this works, but I figured I'd make a note of it. Will report back if I'm able to solve it.
The text was updated successfully, but these errors were encountered: