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

Navigating from prerendered page to non-prerendered page does not trigger hooks #4426

Closed
rmunn opened this issue Mar 23, 2022 · 8 comments · Fixed by #5946
Closed

Navigating from prerendered page to non-prerendered page does not trigger hooks #4426

rmunn opened this issue Mar 23, 2022 · 8 comments · Fixed by #5946
Labels
bug Something isn't working p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc.
Milestone

Comments

@rmunn
Copy link
Contributor

rmunn commented Mar 23, 2022

Describe the bug

When a site has a mix of prerendered and non-prerendered pages, if the first page a client lands on is a prerendered page, getSession will not be called when the client navigates to a non-prerendered page.

This means that if you have a site with a landing page (which is the same for all users) and personalized content (log in to save your todo lists), prerendering becomes a trap. Because if you use getSession to look up the users' data in the database and load their todo lists, that will break as soon as you decide to prerender your landing page.

Reproduction

https://github.com/rmunn/prerender-and-hooks-repro

Run pnpm run dev, then go to / first, which is prerendered. Then click on the navigation link to /userpage, and notice that getSession is not called, so the user page would not be able to present its personalized content.

Navigating directly to /userpage works.

Logs

Actual:
  Handle hook ran for URL /
  getSession was called for URL /

Expected:
  Handle hook ran for URL /
  getSession was called for URL /
  Handle hook ran for URL /userpage
  getSession was called for URL /userpage

System Info

System:
    OS: Linux 5.4 Linux Mint 19.1 (Tessa)
    CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
    Memory: 6.51 GB / 62.58 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 16.14.0 - /usr/local/bin/node
    Yarn: 1.22.17 - /usr/bin/yarn
    npm: 7.23.0 - ~/.local/bin/npm
  Browsers:
    Chrome: 74.0.3729.169
    Firefox: 96.0.3
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.33 
    @sveltejs/kit: next => 1.0.0-next.302 
    svelte: ^3.44.0 => 3.46.4

Severity

serious, but I can work around it

Additional Information

I can work around this by adding router = false to the landing page which I've marked as prerender = true. But the current behavior, where prerendering one page changes the behavior of a different page (whose handle and getSession hooks no longer run) seems wrong to me. The https://kit.svelte.dev/docs/hooks documentation is quite clear that hooks for prerendered pages run at build time, but I expected that that meant that handle and getSession hooks would only run for non-prerendered pages, not that they would never run at all if a prerendered page was the first page visited on the site.

So either this is a bug, or it's a case of unclear documentation.

@Rich-Harris Rich-Harris added the bug Something isn't working label Apr 4, 2022
@Rich-Harris Rich-Harris added this to the 1.0 milestone Apr 4, 2022
@Rich-Harris
Copy link
Member

Ah, interesting! I wonder what the ideal solution is when landing on a prerendered page:

  • Populate session in the background
  • Populate session on the first navigation
  • Populate session on the first navigation to a non-prerendered page

The first option means wasted requests for visits that don't involve non-prerendered pages, and also means that we need to be able to distinguish between static sites and those that can dynamically render stuff (though it could be as simple as requesting /_app/session.json and making that a static file in the adapter-static case).

The second option slows down the first navigation; the third option slows down the first navigation to a non-prerendered page, and also requires the client-side router to distinguish between prerendered and non-prerendered pages.

@rmunn
Copy link
Contributor Author

rmunn commented Apr 5, 2022

FWIW, the third option is the way I thought it worked from reading the docs.

@hessel-bb
Copy link

How can I work around this? I am facing this issue with my dashboard. In my hook, I decode my JWT token and store the user in locals.user but when I redirect to my dashboard after login, I have to reload the page in order for the user info to appear in the navbar.

note: In the navbar I use import { session } from "$app/stores";

@rmunn
Copy link
Contributor Author

rmunn commented Apr 9, 2022

@hessel-bb - Did the router = false workaround posted in my issue description not work for you?

@rmunn
Copy link
Contributor Author

rmunn commented Apr 13, 2022

Looks like #4545 will also provide another possible workaround, setting a sveltekit:reload attribute on any <a> elements in the affected page(s). It's not a very good workaround compared to using router = false, but it's worth mentioning.

@Nickersoft
Copy link

Nickersoft commented May 4, 2022

👋🏻

I'd just like to chime in here and say I've run into this same issue! I almost opened a ticket for it awhile back, but wasn't sure if this was intended behavior or not. I'm currently using goto() to navigate my users post-login, but getSession() is never called, so the session in my landing page's load() function doesn't have any user data.

Right now I'm just calling document.location.replace() manually to trigger a full-page reload. It'd be nice if getSession() could be called without forcing a full re-render, or if there's a way to specify this without fully disabling routing.

Also, I think there are similar discussions happening over in #3722 and #1726.

@coryvirok
Copy link
Contributor

Also chiming in :)

Wouldn't it be possible to include the session in each response to __data.json? That way, every request to the server would trigger a call to getSession() and the session would be included in every response. The browser-side logic to handle __data.json responses would parse out the session info and update the $session store in the browser.

I think this would solve a bunch of problems, including the ones above as well as #1726.

It would also make calls to /endpoint/__data.json result in the same user experience as requests to /endpoint since getSession() would be called for both vs right now /endpoint/__data.json cannot modify the client-side session.

@benmccann benmccann added the p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc. label Jul 19, 2022
@WhyAsh5114
Copy link

I am also struggling with this, I thought it was my code that messed up 🙃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants