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 url navigation when window.___history does not exist #2667

Merged
merged 27 commits into from
Nov 13, 2017

Conversation

efallancy
Copy link
Contributor

@efallancy efallancy commented Oct 29, 2017

This PR relates to #1838 . This would particularly fix the history.push for when window.___history does not exist, especially when no page found and the web host would serve 404.html page. Also, gatsby-link depends on window.___navigateTo and that also depends on window.___history to navigate between pages.

@KyleAMathews I hope this shall be able to fix the problem with navigating in 404 pages.

@gatsbybot
Copy link
Collaborator

gatsbybot commented Oct 29, 2017

Deploy preview ready!

Built with commit a4feba9

https://deploy-preview-2667--gatsbygram.netlify.com

if (window.___history) {
window.___history.push(pathname)
} else {
window.location.href = pathname
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @KyleAMathews , based on my investigation, gatsby-link uses window.___navigateTo to navigate between pages and window.navigateTo relies on window.___history to navigate. Apparently, when a resource/page not found in the directory, the host will use 404.html to serve page not found and window.___history does not seem to exist. Hence, using window.location.href to navigate between pages.

@KyleAMathews
Copy link
Contributor

Nice investigative work!

This doesn't seem like the right fix though — is there any reason we can just ensure our history object is placed on ___window before 404 handling happens?

@KyleAMathews
Copy link
Contributor

Deploy preview failed.

Built with commit 5fa690e

https://app.netlify.com/sites/using-glamor/deploys/59f7ae20a6188f5421feeb84

@efallancy
Copy link
Contributor Author

I thought about it too before thought. Just that I have not dig into finding a way to ensure that the window.___history persist. I'll have a look at it later. Was thinking if probably when scripts being loaded, we can ensure or potentially inject it if window.___history not found? If we can get window.history, I sure believe we can get window.___history as well. 😄

@efallancy
Copy link
Contributor Author

efallancy commented Oct 31, 2017

@KyleAMathews i just skimmed through just now and was wondering would it be fine to just attach/assign the history immediately right after line 24.

Since window.___emitter and window.___loader assigned at the top, that could probably be the reason why it can still be access even when it hits to 404. Also, based on current implementation, the attachment of history is done in router (attachToHistory(routeProps.history)), as well as checking. Any thoughts? 😄

@KyleAMathews
Copy link
Contributor

Went to https://deploy-preview-2667--gatsbyjs.netlify.com/sdfsdf and still couldn't click to another page so looks like something is still broken.

@efallancy
Copy link
Contributor Author

@KyleAMathews good finding. Was waiting for the notification of review app ready but you manage to got there early 😅

Alright, I'll investigate further later. Sorry about that. Thanks for confirming 🙇

@@ -163,7 +163,8 @@ apiRunnerAsync(`onClientEntry`).then(() => {
})
} else {
return createElement(ComponentRenderer, {
location: { page: true, pathname: `/404.html` },
page: true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it into this way instead, since ComponentRenderer is accepting and accessing page props instead of getting it from location props.

@@ -61,7 +61,10 @@ class ComponentRenderer extends React.Component {
// This is only useful on delayed transitions as the page will get rendered
// without the necessary page resources and then re-render once those come in.
emitter.on(`onPostLoadPageResources`, e => {
if (e.page.path === loader.getPage(this.state.location.pathname).path) {
if (
loader.getPage(this.state.location.pathname) &&
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This could possibly be that the page resource might not exist. Putting a checking to guard from having to encounter error at this part.

@efallancy
Copy link
Contributor Author

efallancy commented Oct 31, 2017

Hi @KyleAMathews 😃

Based on this line of code for registering service worker, is there a way that we sort of being able to not always give a false alarm preventing the window to be reloaded? It seems to trigger multiple re-rendering in ComponentRenderer or as long as page not found (called bygetResourcesForPathname through findPage method), that line of code will cause the window to reload, though we do know that the page does not exist.

If we would like to preserve using window.___history or window.___navigateTo, what I can see is that we need to call the callback function to be able to ensure the history is attached to the window. Other than that, the alternative is to use window.location.href (which I know is not favourable) 😅

Let me know what you have in mind as I could have overlook something 😺

Edit: Out of curiosity, I notice we have this line here to check for resources and run the DOM rendering through callback. Any reason for that being implemented that way compared to implementing it not through callback? Just like how it's done in root file 😅

@KyleAMathews
Copy link
Contributor

Hey, what's the status of this?

@gatsbybot
Copy link
Collaborator

gatsbybot commented Nov 2, 2017

Deploy preview ready!

Built with commit a4feba9

https://deploy-preview-2667--using-drupal.netlify.com

@efallancy
Copy link
Contributor Author

Hi @KyleAMathews , I am not particularly sure how to go forth from here. I would need your advice on this. Here's what I found:

  1. In order to be able to ensure history is attached to window, we will need to execute the callback inside loader.js in line 251 . However, this would cause the page to reload and causes the flash in the screen, just like how it's being describe in Fix 404 navigation #2000 . This is happening due to unregistering of service worker inside getResourcesForPathname. getResourcesForPathname is being called inside component-renderer and production-app.

  2. To attach the history in top level might not work if no DOM being mounted and the 404 page that being served are just static page.

  3. The last resort would be on using window.location.href if window.___history not defined. This might not be preferable though 😐

Also referring to the old comment above, I notice that the DOM rendering has different approach compared to production and non production environment.

I hope you'll be able to point out what I went wrong or what did I miss from here.

@efallancy
Copy link
Contributor Author

efallancy commented Nov 4, 2017

@KyleAMathews I've tried to prevent multiple refresh when page not found. The glitch that appears on the page when page not found is caused by window.location.reload whenever the code passes through the unregistering of service worker (found in getResourcesForPathname in loader.js) . I made a check to only reload the page whenever there's a service worker to be unregister. As for attaching of history, I suppose it should work fine on your end too. It pretty much uses the same way as how it's initially proposed in #2000

Let me know what you think or have in mind 😃

Edit: Apologies 🙇 I might get it wrong as I notice reloading also triggered by the emitter onPostLoadPageResources. Also notice multiple remounting behaviour too.

@revolunet
Copy link

thanks for working on that 👍 😍

@@ -249,7 +254,8 @@ const queue = {

if (!page) {
console.log(`A page wasn't found for "${path}"`)
return
cb()
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this just be return cb()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@KyleAMathews ah yes. You're right. I need to update this to be return cb()

@KyleAMathews
Copy link
Contributor

Well looks like you're making progress :-)

Can go to https://deploy-preview-2667--gatsbyjs.netlify.com/sdfsdf now and click a link.

Not really sure what the blinking is from… looked a bit but don't have time for a deeper dive.

I'd be fine merging this if you're running out of time to keep investigating as it's an improvement over what we have now or feel free to keep searching.

@efallancy
Copy link
Contributor Author

@KyleAMathews I'm happy for you to merge it if you're happy with it 😄

I can do the search outside on different issue or PR. Also, if the inability to click on any link when page not found in production has impact on most app, I reckon we might need to merge.

@KyleAMathews
Copy link
Contributor

Thanks for all your work @emmafallancy! Let's put this out there!

@revolunet
Copy link

revolunet commented Nov 13, 2017

thanks ! 👏

@efallancy
Copy link
Contributor Author

Thanks @KyleAMathews 😄

@ferdinandsalis
Copy link

@emmafallancy just a heads up I am on v1.9.114 and I am getting this error on a client-only route,
Uncaught TypeError: Cannot read property 'push' of undefined. production-app.js:87:6. The client route is rendered — initially showing the not found page. It seems this issue persists at least with client only routes. Any ideas what might be wrong here?

@efallancy
Copy link
Contributor Author

Hi @ferdinandsalis , thanks for the heads up 😄
Based on the error that you've given, it seems like it couldn't find history that supposed to be attached during initial DOM rendering. It should be made available if you're navigating from a page that has already been rendered.

Would you be able to confirm if this is still happening in v1.9.117 ?

@ferdinandsalis
Copy link

Its still happening with v1.9.117.

@efallancy
Copy link
Contributor Author

Do you have a sample repo that I can have a look at or poke around? I tried poking around with Gatsby's website and it seems that I can navigate around without hitting into the error that you mentioned. I can do a PR but I would actually like to understand how you managed to hit into that error 😅

@KyleAMathews have you encounter this issue before?

What I can confirm is that if the 404 page uses layout, and when user navigate to other page from 404 page and going back again (by pressing back button), the layout will be gone and only renders the content of the 404 page. I can put a PR to this, along with the issue that you've found out.

@ferdinandsalis
Copy link

@emmafallancy thanks for taking a look at this. I will try to get repo up that reproduces the issue. Thanks for your help.

@efallancy efallancy deleted the topic/fix-404-navigate-page branch November 28, 2017 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants