From bda78cab4c9280e971ca47e1efc3623c9412e581 Mon Sep 17 00:00:00 2001 From: Tim Pace Date: Thu, 11 Aug 2022 10:40:52 -0700 Subject: [PATCH] fix: ensure hidden iframe apps render in development mode --- packages/next/client/dev/fouc.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/next/client/dev/fouc.ts b/packages/next/client/dev/fouc.ts index bca480e22719..9d2fafea5314 100644 --- a/packages/next/client/dev/fouc.ts +++ b/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 +// 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) { + 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 { return new Promise((resolve) => { - ;(window.requestAnimationFrame || safeSetTimeout)(function () { + safeCallbackQueue(function () { for ( var x = document.querySelectorAll('[data-next-hide-fouc]'), i = x.length;