-
-
Notifications
You must be signed in to change notification settings - Fork 375
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
All routes are chunked, causing hydration of prerendered pages to flicker #281
Comments
also related #274 |
Let me know how I can help. I might take a stab at seeing what's wrong with the preact-cli Webpack config if I have some time later. |
@ajoslin The async loader was implemented in a way that during prerendering , it act as a normal require so the above behavior is correct (maybe?) But anyway, we should fix this ! |
@thangngoc89 The problem is that it's happening whether or not I use the I've fixed this problem in my app for now by moving my routes into |
@ajoslin ah. So it's because of route spliting behavior of preact-cli |
This is supposed to happen. We also state this in the README:
The As for your issue, you're seeing a content flash, correct? If so then we need to fix that part 😄 |
Got it. I certainly love this feature minus the flicker. And yes, the problem is just the content flash and that it's rendering before the current route's bundle is ready. |
Cool 😃 Do you mind refreshing me by sharing what your |
Sure, here's what they look like (from the repository in the OP): http://ajoslin.co/UzAy0g/4Us7rtzG |
And here's a movie of what the flicker looks like and the network tab: http://ajoslin.co/GIH2Ts/5kzN1wTO |
Thanks, helpful! I see Network throttling, but do you have CPU throttling on too? It seems to be just a really slow render, because the "flash"/re-render only happens once the |
I don't think that's the issue. It does one render right when bundle.js has loaded (3.04s) and then does another after home bundle has loaded (698ms later). You see all of the content (prerendered), then app content only (bundle), then all content again (bundle + home chunk). |
Oh, silly. I didn't pay attention to the Pending status of the |
My first guess is issue with I think we can add a falsey check to inside the |
I don't think the problem is the first re-render, it's the initial render itself. I tried:
Both of these still result in the Async component's content being erased immediately on initial render. Is there an idiomatic way to tell the component render to "keep whatever is inside this element and don't do a vdom diff?" The "hacky" way would be something like this (though even this wouldn't exactly work): render () {
if (!state.child) return <div dangerouslySetInnerHTML={{__html: this.base.innerHTML}}>
} |
Ping @lukeed, if you have a second would you mind commenting on the above? |
Ooh, sorry, hectic week for me -- I'm in the middle of moving. 🚚 I think the truthy As of right now, my theory focuses around the initial javascript render. After reviewing your video clip a few more times (thank you 🙏), the pre-rendered content is, of course, fine. It is only once the app begins to boot up that a full reset + full re-render happens. That points back to this. So, my theory is that:
Inserting a truthy check at (6) or (7) should do the job. |
@lukeed I appreciate the in-depth explanation. That all makes sense. However, I'm just not sure how to accomplish "defer initial render until the current route's chunk is loaded." It doesn't seem like it's as simple as a "truthy check" somewhere. It seems like |
Ping @lukeed if you have a sec could you take a look again at my above comment? |
@ajoslin 🙈 Yes, I'm playing with the templates now. I'll try to come up with a solution & post it here! |
Alright. I appreciate it. I'm still playing with this too, I'll post here if I come up with anything. |
Hacky solution as POC: AsyncComponent emits "asyncComponentLoading" in its constructor, and "asyncComponentLoaded" in its Then the app startup listens for those. entry.js let root = document.body.firstElementChild;
let firstInit = () => {
let app = require('preact-cli-entrypoint');
let isFetchingChunk = false
window.addEventListener('asyncComponentLoading', () => {
isFetchingChunk = true
})
let detachedApp = preact.render(preact.h(app), document.createElement('div'));
if (isFetchingChunk) {
window.addEventListener('asyncComponentLoaded', init);
} else {
init();
}
}
let init = () => {
let app = require('preact-cli-entrypoint');
root = preact.render)(preact.h(app), document.body, root);
}
if (module.hot) module.hot.accept('preact-cli-entrypoint', init);
firstInit();
} The biggest problem with this is that we're mounting the app twice. This means that if any components in the app have side effects on mount, those side effects will happen twice.. we can't really tolerate that. Is there a way to render the app detached, and then attach it later, once the async chunk loads? The alternative to this method (determining a route is going to be async loaded at runtime) is to determine it at compile time with static analysis. Doing that is beyond my scope of knowledge. |
I was putting my efforts into #329 -- now that that's done I can actually put effort into this guy. Been on my mind & want to hack at it 😈 |
@lukeed I had to go into production without route chunking (I moved all of my routes into I know your time is limited & valuable, so I put a $100 bounty on this issue to hopefully enable you to prioritize it: https://www.bountysource.com/issues/47899502-all-routes-are-chunked-causing-hydration-of-prerendered-pages-to-flicker |
Hahaha! Clever move! |
I think I solved it 😃 I'll post later tonight. Time for a walk! |
Yup! Here's a quick video recording. PR underway~ |
@lukeed this can be closed now. Also, please claim the bounty: https://www.bountysource.com/issues/47899502-all-routes-are-chunked-causing-hydration-of-prerendered-pages-to-flicker 💰 |
Just for reference - none of discussed solutions worked for me. Got it working like so
Build result is:
|
This comment has been minimized.
This comment has been minimized.
This issue is 3 years old and the related modules have been rewritten since then, it's exceptionally unlikely you're seeing something unrelated. The current version of preact-cli (3.x) includes asynchronous hydration by default that prevents flickering. |
I got this problem with a latest version |
It appears that all routes are being chunked and async loaded, even without the presence of the
async!
prefix.I've reproduced this using preact-cli 1.4.1 here: https://github.com/ajoslin/preact-cli-issue-all-routes-chunked. Just build and serve and check the network tab, it loads both bundle and route-home.chunk. And it does a render before the home chunk is loaded.
Details
I have a prerendered homepage. Here's the process when the user visits the site:
Between (2) and (4), a version of the app is rendered that does not include the home route's content, because the home route's JS is still loading.
This results in a noticeable "flicker" of the home content being removed then re-appearing as soon as the initial bundle loads.
I'm not using the
async!
prefix when importing my home route, but it looks like the home route is being chunked anyway.The text was updated successfully, but these errors were encountered: