Apps never render in hidden iframes in development mode
See original GitHub issueVerify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: x64
Version: Darwin Kernel Version 21.4.0: Fri Mar 18 00:46:32 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T6000
Binaries:
Node: 14.19.1
npm: 6.14.16
Yarn: 1.22.19
pnpm: N/A
Relevant packages:
next: 12.2.3
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0
What browser are you using? (if relevant)
Chrome 103.0.5060.134
How are you deploying your application? (if relevant)
Contentful app SDK (development)
Describe the Bug
When running NextJS in development mode (e.g. next dev
), apps that are rendered into hidden cross-origin iframes can fail to render.
I first observed this issue when using NextJS to load an application via the Contentful App Framework in development mode. When Contentful loads the application, it does so by requesting a page URL via a hidden iframe. In some instances (e.g. Contentful’s App Configuration screen), the app is not considered “loaded” (and thus remains hidden) until a specific Contentful SDK callback is called. The callback is typically (and specifically in my case) consumed through a React Provider, and thus is is not called until my apps first render cycle is completed.
In development mode, NextJS relies on scheduling and running an animation frame to handle flashes of unstyled content with style-loader
. The problem is that hidden iframes have no guarantees about running animation frames, so while NextJS assumes requestAnimationFrame
is safe to use if it’s available, when used within an iframe, it’s not a reliable way to schedule future work.
I believe the bug can be fixed by only relying on requestAnimationFrame
if the window
object is not contained within an iframe (can detect size of window too to be extra safe).
I was able to work around this bug by running this snippet of code before rendering the app:
if (typeof window !== 'undefined' && window.self !== window.top) {
window.requestAnimationFrame = window.setTimeout;
}
Expected Behavior
Although the iframe is hidden, we should still render the app.
Link to reproduction
about:blank
To Reproduce
Apologies for no reproduction link. I couldn’t easily reproduce this in other environments.
Hoping the bug description and related source code link + article is enough to illustrate the issue
Issue Analytics
- State:
- Created a year ago
- Comments:10 (9 by maintainers)
Top GitHub Comments
You might have missed some important details in my bug description. I linked that line of code too, but the problem is that
requestAnimationFrame
is available, but just not trustworthy. In thewindow.requestAnimationFrame || safeSetTimeout
selection,requestAnimationFrame
gets selected, but the callback never fires.You can check out this article as to why it’s not firing the callback, even though
requestAnimationFrame
is defined and available.In fact, given that this is such a niche issue… I’d love to use it as an opportunity to open a PR and contribute. Doesn’t look like a high priority bug for the vercel team to fix.