loteoo / hyperstatic

Routing, prerendering, code splitting and prefetching for hyperapp
https://hyperstatic.dev/
MIT License
59 stars 5 forks source link

Router implementation alternatives #12

Open skipkayhil opened 4 years ago

skipkayhil commented 4 years ago

The current implementation of the router (depending on parsing the current DOM into virtual nodes) seems like not very good practice and is definitely not declarative. I have two potential alternatives that I would be willing to implement to resolve this.

  1. Continue to show only loaded content but in a more declarative way.
  2. Change to a more basic 'loaded content or fallback loading spinner' type approach

For 1, I believe I have a solution where state of a new route will be held until that route has been loaded, and then it replaces the active route in state. This would allow the page to stay interactive until the new page has loaded. Clicking a different link before the page has loaded could result in the new page replacing the new route in state, or other Links could be locked until the route of the first link clicked has loaded.

Let me know if you have any suggestions or questions, and I can work to implement one of these solutions

loteoo commented 4 years ago

Hi there @SkipKayhil, I'm glad you're bringing the router up. Thank you for the contribution to the project by the way, it is really appreciated.

I think 1 is the best way to go, since the whole point of hyperstatic (IMO) is to avoid 2.

I'm also unsure of what you mean in your solution for 1. It seems you are describing another problem but I might be wrong. I've detailed some info on the problem below if it can help.

I actually spent multiple hours in the last weeks trying to hack ways to get rid of the htmlToVdom thing. I absolutely hate it, but it's the only way I found to make this work right now.

I'm going to try to clarify the reason it exists below:

Basically, when the hyperapp app loads, no "pages" bundles are loaded at all (including the one for the current page). Only hyperapp and hyperstatic is loaded. The code that lives above the router is loaded as well (ex: header / footer), but the code for the page itself is not (since it's under the router). The ParseUrl action then sees that the page matching the current URL is not loaded and loads it asynchronously.

Since the pages are pre-rendered, if we don't parse the existing dom into vdom (which would happen if we remove the block of code at line 30 in router), this is what would happen:

  1. Full pre-renrered HTML gets rendered
  2. Javascript kicks in, hyperstatic loads and does not have the code for the current page, so it completely removes the pre-rendered content from the page and displays a small "loading..." message instead.
  3. Code for the page loads, and renders it to the page again.

All of this would end up creating a flash of content on first page load, which is basically one of the most important problem hyperstatic tries to solve in the first place.

Notice that this is only a problem on the first page load (or full page refresh). The htmlToVdom function never gets run again after that first page load, since there is always at least 1 view that is available to be rendered. (either current or next page)

Here the two solutions that I think would solve the problem, but that I have not found a way to implement yet.

  1. Have the code of the current page be already available to hyperstatic on the first render. Instead of looking for existing DOM and parsing it to vdom, it would be better if the bundle of the page itself was ready to go, as if it was already fetched by the TriggerPageLoad action.)

  2. Find a way to tell hyperapp to not destroy some part of the existing DOM when it first renders.

I think 2 is the best option performance wise, and also implementation wise since it would be very little code, but it might also be not possible at all.

Let me know what you think about all this!! Thanks again for your time investment in this!