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

Feat: SPA-like clientside navigation #1609

Closed
marvinhagemeister opened this issue Aug 8, 2023 · 11 comments · Fixed by #1824
Closed

Feat: SPA-like clientside navigation #1609

marvinhagemeister opened this issue Aug 8, 2023 · 11 comments · Fixed by #1824
Labels
feat New feature or request
Milestone

Comments

@marvinhagemeister
Copy link
Collaborator

Currently, when you click on a link in Fresh we leave it up to the browser what to do. The browser unloads the page, and builds the new page from scratch again. This has benefits in that it makes the whole system pretty simple. This is usually referred to as Multi-Page-App style routing (=MPA).

But there are real benefits for doing these things client side. There is usually a short flash of a white page depending on the browser when the user navigates to a new URL. Any component state of active components is completely destroyed and developers need to keep track of that themselves. In contrast to that, a more single-page-app style routing (=SPA) solution makes the app feel much more "app-like" and responsive. There is less flashing of the screen and being able to keep component state around is often pretty useful.

Whilst working on Fresh's capabilities to nest islands in Fresh 1.3 and a little bit for the upcoming 1.4 release, I've done some exploration in this space and think found a path forward which fits well into Fresh's philosophy and is way less code than expected. As a side effect, this is also the missing bit to make view transitions really nice in Fresh (first attempt here #1532 ).

Mostly making this issue to keep track of the progress on that.

@marvinhagemeister marvinhagemeister added the feat New feature or request label Aug 8, 2023
@guifromrio
Copy link

guifromrio commented Aug 9, 2023

That's a promising exploration!

Have you thought about approaches in the spirit of HTMX in order to leverage server side rendering but avoiding the full navigation? Hono is exploring in that direction, might be worth a chat https://blog.yusu.ke/hono-htmx-cloudflare/

We have some examples of customers who weren't pleased with server side navigation for SKUs for example (https://beta.aviator.com.br/camisa-oxford-caqui-camisa-oxford-caqui-caqui/p). Might be a great use case to test client side navigation in a real world fresh site.

@marvinhagemeister
Copy link
Collaborator Author

Have you thought about approaches in the spirit of HTMX in order to leverage server side rendering but avoiding the full navigation?

Yes, that's what I was referring to in our call two months back. The bit we need to add on top of that is a bit of logic so that islands are revived and continue to work. I figured that part out recently and mostly need the time now to be able to site down and write it.

Yeah good point. E-Commerce is a good example on where full page navigation are often not optimal as there are lots of small areas which need new data.

@guifromrio
Copy link

@marvinhagemeister Hi there! Our fresh-based admin is now struggling with performance precisely because sometimes we opt to do a full re-render when what we actually wanted was a partial reload of one specific part of the HTML (which is not even visible at all times, sitting behind a tab). We are going to reach for a hand-rolled client side solution, but discussing this we remembered this issue and thought we might check on the progress, or if we can offer some implementation help to get this published :)

@marvinhagemeister
Copy link
Collaborator Author

@guifromrio thanks for reaching out. I share your vision that partial reloads have lots of potential for performance. Would love to hear your implementation plans. I've tried a couple of different approaches so far and whilst I feel like I'm getting closer to something that feels right, I feel like I'm not there yet.

@marvinhagemeister
Copy link
Collaborator Author

I think I cracked it. Got most of it working and I'm currently ironing out edge cases. The way it works is that there is a slot component that marks areas where insertions can happen. Instead of the model of htmx where one request can only insert into a specific selector, this model allows you to update many unrelated areas on the page with one single HTTP request. All of this works with islands instance preserved which was the tricky thing to implement.

Here is a quick demo of it. I know it's not the prettiest, but it shows that it works. We have two islands (counters) and on clicking any of the two links the content on the page is updated based on the html response from the server. Notice how after the server content is injected (the orange flash) that both counter states are preserved.

fresh-partials.mp4

@guifromrio
Copy link

That is AMAZING!! Excited to build on top of that!!!

@petersahanaya
Copy link

petersahanaya commented Oct 6, 2023

yeah i hope, fresh can make an app that still a sea of HTML and an island of Javascript. Without needed to refresh the whole content on each route changes. So it feels like SPA but in "fresh" style. I hope you guys are working on that, Thank you Fresh Team.

Sorry about my english

@marvinhagemeister
Copy link
Collaborator Author

@petersahanaya this feature has landed in main in the past week. It will be part of the next Fresh release.

@guifromrio
Copy link

But if you don't want to wait, we have already shipped Partials support in deco.cx! https://www.deco.cx/docs/en/developing/partial

@sonickseven
Copy link

I think I cracked it. Got most of it working and I'm currently ironing out edge cases. The way it works is that there is a slot component that marks areas where insertions can happen. Instead of the model of htmx where one request can only insert into a specific selector, this model allows you to update many unrelated areas on the page with one single HTTP request. All of this works with islands instance preserved which was the tricky thing to implement.

Here is a quick demo of it. I know it's not the prettiest, but it shows that it works. We have two islands (counters) and on clicking any of the two links the content on the page is updated based on the html response from the server. Notice how after the server content is injected (the orange flash) that both counter states are preserved.
fresh-partials.mp4

Can you share me the code of this example, I use tag "a" but my page refresh when I change of page 😭

@marvinhagemeister
Copy link
Collaborator Author

@sonickseven Check out the page about Partials in our documentation: https://fresh.deno.dev/docs/concepts/partials

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants