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

fix: ensure hidden iframe apps render in development mode #39514

Merged
merged 2 commits into from Aug 11, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 15 additions & 3 deletions packages/next/client/dev/fouc.ts
@@ -1,12 +1,24 @@
// This wrapper function is used to avoid raising a Trusted Types violation.
const safeSetTimeout = (callback: () => void) => setTimeout(callback)
// This wrapper function is used to safely select the best available function
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of the issue:

  1. Hidden iframes are not guaranteed to ever run callbacks schedule through requestAnimationFrame. This table breaks it down browser to browser. For example, on Chrome, window.requestAnimationFrame is available, but the callback is never called in a hidden cross-origin iframe.
  2. displayContent (below) is passed as an option to beforeRender which is specifically await-ed before hydrating the app. If displayContent never resolves, the app never hydrates.

// to schedule removal of the no-FOUC styles workaround. requestAnimationFrame
// is the ideal choice, but when used in iframes, there are no guarantees that
// the callback will actually be called, which could stall the promise returned
// from displayContent.
//
// See: https://www.vector-logic.com/blog/posts/on-request-animation-frame-and-embedded-iframes
const safeCallbackQueue = (callback: () => void) => {
if (window.requestAnimationFrame && window.self === window.top) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though the issue is with hidden iframes, I think it's safe to scope this check to iframes in general (given that this is a dev feature. Open to feedback here and can also detect if it's hidden or not here.

window.requestAnimationFrame(callback)
} else {
window.setTimeout(callback)
}
}

// This function is used to remove Next.js' no-FOUC styles workaround for using
// `style-loader` in development. It must be called before hydration, or else
// rendering won't have the correct computed values in effects.
export function displayContent(): Promise<void> {
return new Promise((resolve) => {
;(window.requestAnimationFrame || safeSetTimeout)(function () {
safeCallbackQueue(function () {
for (
var x = document.querySelectorAll('[data-next-hide-fouc]'),
i = x.length;
Expand Down