WordPress / wordpress-playground

Run WordPress in the browser via WebAssembly PHP
https://w.org/playground/
GNU General Public License v2.0
1.61k stars 244 forks source link

Missing CSS and images because the Gutenberg iframe isn't controlled by the service worker #646

Open Lovor01 opened 1 year ago

Lovor01 commented 1 year ago

This happens only in https://playground.wordpress.net/, when run locally as VS code extension, the issue does not appear.

Block inserter "+" icon is not styled; some other UI elements (like buttons when inserting new image block, buttons on starter template on columns block, etc) are not styled as well; when inserting new image and uploading it through interface, the image does not show in block editor.

Tested on Firefox developer version 118 b9 and Chrome dev version 118 on Windows 10.

Steps to reproduce: Start new WP instance in playground. Create new post, insert image from local file.

code-flow commented 12 months ago

Same here (latest MacOS Firefox and Chrome). Anyone know how to fix this?

adamziel commented 12 months ago

Network inspector shows a bunch of 404s for URLs like https://playground.wordpress.net/scope:0.5858414608182674/wp-includes/css/dist/block-editor/style.min.css?ver=6.3 which originate from an iframe rendered by Gutenberg. That iframe has src="blob:https://playground.wordpress.net/9c82f60a-1f1e-4abe-adde-6b5b62f51043" and I'm almost certain it's considered cross-origin and thus the requests it issues are not handled by the service worker. It's this issue all over again:

https://github.com/WordPress/wordpress-playground/issues/42

I'm not sure what the fix is yet.

adamziel commented 11 months ago

Here's what I found:

Here's the script I used to verify the above:

async function init() {
    // Register a service worker
    await navigator.serviceWorker.register('/sw.js', { scope: '/' });
    console.log('Registration successful');
    // Reload the page after the first time this script runs

    // Now, confirm the top-level script is controlled by the service worker
    console.log("I'm an top-level script", {
        origin: window.location.origin,
        swController: navigator.serviceWorker.controller
    });

    // Let's create a blob-based iframe and check if it's controlled by the service worker
    const blob = new Blob([`
    <html>
        <body>
            <h1>Test iframe</h1>
            <script>
                console.log("I'm an iframe", {
                    origin: window.location.origin,
                    swController: navigator.serviceWorker.controller,
                    protocol: window.location.protocol
                });
            </script>
        </body>
    </html>
    `], { type: 'text/html' });
    const blobUrl = URL.createObjectURL(blob);
    const iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    iframe.src = blobUrl;

    // And sadly, the iframe is not controlled by the service worker :-(
}
init();
adamziel commented 11 months ago

To sum it all up:

URL-based src like src="/doc.html" seems to be the only way forward. Or am I missing something? cc @dmsnell

@ellatrix can you remember what was the rationale behind using a blob vs a URL? Was it saving an extra request and figuring out the right file path? Would it be viable to create an extension point to enable forcing src="file.html" in Playground?

dmsnell commented 11 months ago

no idea @adamziel, though I think the blob has memory implications for Gutenberg.

ellatrix commented 11 months ago

We switched to blob to fix the origin issue, it's also a bit cleaner that srcDoc. Why does it need to be controlled by the service worker? It's purely added in JS, nothing server side? Are we talking about the editor content iframe or something else? I thought everything was working fine?

adamziel commented 11 months ago

@ellatrix the root problem was always the service worker not handling the requests from the editor content iframe – like loading style.css for specific blocks. When it does, we say the iframe is controlled by the service worker.

In our chat I somehow reached a wrong conclusion. I thought that the iframe only needs to have the same origin to be controlled. It doesn't. The blob-based editor content iframe now has the same origin as the top-level page, but it still isn't controlled. The only way I was able to make it controlled was by using a path-based src like src="/document.html"

adamziel commented 11 months ago

We'd need to revert https://github.com/WordPress/gutenberg/pull/50875 in Gutenberg, but then the original issue it solved would return:

The problem with srcDoc is that window.location is not filled, so relative hash links will trigger a navigation change and reload the page. It would also remove the need for a hack in WP playground.

For now I'll see if I can patch this in Playground to fix all the 404s, and then let's see what a proper solution would look like. cc @ellatrix

Edit: This is more difficult than just swapping src={blob} with src={url} because the initial document now loads all related CSS assets. Hm.

Edit 2: This worked for me locally:

In WordPress/Gutenberg:

src: '/wp-includes/empty.html?doc='+encodeURIComponent(renderToString( styleAssets ))

In empty.html:

<!doctype html>
<script>document.write(decodeURIComponent(window.location.search.substring(5)))</script>

However, this creates an XSS vulnerabilty. It's fine for Playground since you can run custom code anyway, but it wouldn't work for WordPress core at all. I do not see a single solution that would suit both WordPress core and Playground here and we may be stuck with patching that part of WordPress until there is one.

bfintal commented 11 months ago

Encountered this as well during the brief period the Live Preview button was in the Plugin Directory. A bunch of 404s and unstyled content of the Block Editor.

Was using latest Arc on latest MacOS.

Would recommend making this urgent issue.

ellatrix commented 11 months ago

URL-based src like src="/doc.html" seems to be the only way forward. Or am I missing something? cc @dmsnell

It's using a blob URL, no? 😉

adamziel commented 11 months ago

Sure it does @ellatrix. Let's call them HTTP URLs and blob URLs then :p

adamziel commented 11 months ago

Short-term fix coming in https://github.com/WordPress/wordpress-playground/pull/668 Long-term fix is being explored in the Gutenberg repo at https://github.com/WordPress/gutenberg/pull/55152

adamziel commented 11 months ago

668 just landed and I'm about to deploy it to playground.wordpress.net. Let's keep this issue open until the upstream Gutenberg PR gets resolved in one way or another.