Skip to content
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

Turbo should wait for new CSS to be loaded before rendering new pages/frames #613

Open
manuelpuyol opened this issue Jun 28, 2022 · 3 comments

Comments

@manuelpuyol
Copy link
Contributor

CSS is a render blocking resource, so normally the browser will wait for it to be loaded before continuing rendering the page.

When navigating using either Turbo Drive, Turbo will add new Stylesheets coming from the response to the head, but won't wait until they are loaded to render the new body, causing jitter in the page in case the new CSS changes the layout.''

In this (extreme) example, I'm throttling the request to a CSS file by 1s to showcase the bug:

Screen.Recording.2022-06-28.at.3.19.49.PM.mov

Using the same throttle, but with data-turbo="false":

Screen.Recording.2022-06-28.at.3.21.40.PM.mov
@seanpdoyle
Copy link
Contributor

seanpdoyle commented Jun 28, 2022

Thank you for opening this issue!

I wonder what our options are for synchronizing their load times.

Maybe we could attach load and error listeners to <link> elements when a <turbo-frame> response contains a new element, transform those into Promise instances, then incorporate them into the Frame resolution.

function waitForLoad(element: HTMLLinkElement): Promise<void> {
  return new Promise((resolve, reject) => {
    const onLoad = () => {
      element.removeEventListener("error", onError)
      resolve()
    }
    const onError = () => {
      element.removeEventListener("load", onLoad)
      reject()
    }

    element.addEventListener("load", onLoad, { once: true })
    element.addEventListener("error", onError, { once: true })
  })
}

const linkElementsLoadedInFrameResponse = ...

await Promise.all(linkElementsLoadedInFrameResponse.map(waitForLoad))

@manuelpuyol
Copy link
Contributor Author

I have #614 for visits, but I couldn't find how Frames deal with new CSS. I see

activateScriptElements() {
for (const inertScriptElement of this.newScriptElements) {
const activatedScriptElement = this.createScriptElement(inertScriptElement)
inertScriptElement.replaceWith(activatedScriptElement)
}
}

but nothing for stylesheets

@jody90
Copy link

jody90 commented Oct 24, 2023

I encountered the same problem. Is there already a solution for the behavior in frames?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants