-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Streaming promises broken on Safari (due to Safari not rendering incomplete response) #10315
Comments
This might be related: |
I don't know if this approach is reliable. Perhaps it's better to use SSE or ws for this feature. |
There's nothing actionable on SvelteKit's side - if Safari doesn't support streaming promises (hopefully only with chunks below a certain threshold as indicated by #9154) then there's nothing we can do about that. How would a solution look like that solves this? I don't see one. |
Upon further investigation, I noticed that adding some more bytes to the initial response caused Safari to start rendering the first chunk of data before waiting on the second. However, if the initial chunk is not large enough, Safari doesn't render in chunks at all but waits for the entire response to be completed. Actually, when I made the issue, I had a slightly wrong impression of how SvelteKit was accomplishing this. (I noticed that the responses weren't sending Still, although I am not intimately familiar with HTTP standards, based on the research I've done, I don't believe that this type of "progressive rendering" should be relied on for this feature. In the end, it's up to the browser to decide when to start rendering chunked content. The primary purpose of That is, it's not part of any standard that browsers must begin to render chunks as they come in. Rather, this is an optimization technique that certain browsers have implemented in order to make pages seem to load more quickly to the end user, even if they have not been completely received. We should not take this implementation-specific optimization behavior for granted — it's not predictable nor guaranteed and may change on a whim. Especially since it is not advertised anywhere in the SvelteKit docs that this feature may be unreliable (which it has proven to be, through this issue as well as #9154). Maybe we can explore rebuilding this "streaming promises" feature through something like Server-Sent Events? SSE is a standardized and well-supported feature that is specifically intended for purposes such as these. |
I also noticed that in Safari, it's not simply the byte size of the chunk that determines whether Safari will start rendering. For example, none of the following got Safari to start "progressive rendering" for me:
Seems like it only starts when there is some threshold amount of "real content", by some metric, to display. More hints as to why we shouldn't try to rely on this behavior... |
SSE most likely is not an option, as it's not supported by many of the platforms Kit sites are deployed to. |
The only way to "fix" this that I can think of is: Rather than sending one response to the browser that finishes streaming whenever all outstanding promises are resolved, send a response to the browser that contains unresolved promises for all of the deferred data, along with code to initiate a client-side FWIW, this problem also affects Next.js's streaming- |
Maybe we just need to lean back and wait, now that streaming is becoming more popular, browser will surely feel pressured to do something about this. |
From my testing Safari only renders HTML chunks larger than around 512 bytes of rendered content for See the bug report here: https://bugs.webkit.org/show_bug.cgi?id=252413 It's possible that it'll only affects smaller websites (like demos) but I'm not sure. |
In any case, I think it's best for everyone to make a note in the docs that this feature may not work on some browsers. |
To solve this issue, as mentioned in this Remix GitHub issue, you can add the following code to the layout or any pages that use streaming:
|
@timootten what does this even do? |
@Antonio-Bennett |
@timootten ahhh okay makes sense thanks for the explanation |
Describe the bug
Streaming promises, i.e., returning a nested promise in a server-side data loader, doesn't work properly in Safari.
I believe the way SvelteKit attempts to accomplish this is by first sending the initial HTML document, keeping the connection alive, and then finally ending the response with another script tag that patches the previously sent HTML.
However, this would rely on the browser starting to render the document before the response is fully received, which is not something that should be taken for granted — Safari, for example, does not do this, and waits for the response to be fully received before rendering the page. That means, if the promise takes 10 seconds to resolve, the page will not begin to load (and not show the loading state as intended) for the entire 10 seconds, before finally loading with the data fully rendered.
Comparison between the two browsers:
CleanShot.2023-07-03.at.19.53.55.mp4
Reproduction
Repository: https://github.com/Rich-Harris/sveltekit-on-the-edge
Relevant line
Relevant lines
Reproduction steps:
Logs
No response
System Info
Severity
serious, but I can work around it
Additional Information
No response
The text was updated successfully, but these errors were encountered: