-
-
Notifications
You must be signed in to change notification settings - Fork 29
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
Frontend Routing #197
Frontend Routing #197
Conversation
Build is failing on unrelated test cases... |
Progress so far: I've got the two entry points defined, and I've simply lifted the existing Ugly, basic, but working. The next thing will be to replace the hash based navigation with something more general purpose, and to clean up the API so that the requirement is for you to provide a simple function like this: def router: Location => Msg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, just added a few comments 😄
You may see failing builds here, but it's a flaky test... #199 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, nice as a starting point.
@hobnob & @bilki: I've resolved the old discussion points, either by fixing them or because they're out of date - hopefully I didn't missing anything. (cc @DeamonDev in case you have any thoughts on this. Note that I'm not planning to bake any third party url parsing libs into Tyrian directly, but it would be ideal if this solution optionally worked with libs like This all works, but it needs more thought. Problem 1 - HyperlinksThe first (and maybe main) problem is that you need to set hyperlinks like this at the moment: a(href := "#", onClick(Msg.NavigateTo(page)))("my link") Rather than the more desirable (I think? Probably better for accessibility too?): a(href := "/my-page")("my link") To make the latter work, I think we'd have to somehow set <a href="/my-page" onclick="event.preventDefault()">my link</a> The catch with that is that I think I'd have to patch it into the runtime somewhere as a special case. 🤔 Problem 2 - Routing UXThe second problem is the routing function. I thought this was all going smoothly until I realised just how nuanced routing can potentially get. 😅 At the moment I've dodged the problem by introducing a Do we need to do that now? Could it be a future enhancement based on user feedback? Looking up how other frameworks do this is a bit of a minefield. Recommended reading suggestions welcome. Problem 3 ...what have I missed?I'm super confident that there is more complexity here I'm missing because I'm sort of building this in abstract without a concrete use case. Suggestions welcome. |
Looks good Dave! You're right that the second option for The question of how to achieve it though is a little tricky 🤔 I wonder if we could modify the Additionally, you could also create a new final case class Route(baseUrl: String, path: String, routeParams: Seq[String]) {
}
object Route:
def apply(path: String, routeParams: Seq[String]): Route = Route("", path, routeParams)
def apply(path: String): Route = Route("", path, []) The benefit here would be that you could do a check against a string (such as a URL) against a route, and could also use a base URL in case you were using Tyrian in a subfolder on a main site (such as a blog) without having to change loads of code if the Base URL changes. Hope that helps 🙂 |
Thanks @hobnob - I've mulled it over and it's a good idea as a way to give us a hook to decide what to do next, I will need something like that. I would like to avoid adding a non-standard entity into the markup however (if possible). Ideally if you can HTML, you should be able to Tyrian (and if you can't HTML, you can google HTML and apply almost 1:1). (Have we already added non-standard stuff with the events? Maybe? Gah! 🤔) As usual, all roads lead to Elm. I've had a bit of a snoop around what they do (I haven't read the code, just mooched around the docs to borrow wisdom) and if applied directly, I think it goes something like this:
This isn't a perfect translation of the Elm solution, but I think this is the broad strokes of what the shape of the solution needs to be. No doubt I'll discover more problems along the way. On reflection, I think some of this goes towards a suggestion @bilki had in an earlier comment around having some generic nav types. |
This version has a few warts, but appears to work correctly. There's a couple of TODOs to address (called out in comments), and the only other thing is that the initial routing has to happen last, by which time we've briefly (like a flicker) rendered the homepage even if we want some other page. |
Also, I suspected this wouldn't work so I've added an external link to the sandbox, and clicking that produces an error.
|
Getting there, two outstanding issues that I know about:
UPDATE: |
I think I'm done with this now. The end result is that Your Tyrian web app will now need to implement
def router: Location => Msg = Routing.externalOnly(Msg.NoOp, Msg.FollowLink(_)) I've also made
def router: Location => Msg =
case loc: Location.Internal =>
loc.pathName match
case "/" => Msg.NavigateTo(Page.Page1)
case "/page1" => Msg.NavigateTo(Page.Page1)
case "/page2" => Msg.NavigateTo(Page.Page2)
case "/page3" => Msg.NavigateTo(Page.Page3)
case "/page4" => Msg.NavigateTo(Page.Page4)
case "/page5" => Msg.NavigateTo(Page.Page5)
case "/page6" => Msg.NavigateTo(Page.Page6)
case _ => Msg.NoOp
case loc: Location.External =>
Msg.NavigateToUrl(loc.href) The I imagine that you could also decide to pull in some fancy url parsing library to build a clever router here if you liked. Once you've done your routing, you'll want to use some of the new |
The aim of this PR is to build frontend routing into Tyrian.
The plan is to do the same as Indigo, i.e. depending on which initial trait you extend you get different behaviour. In this case,
SinglePage
is the replacement forTyrianApp
, andMultiPage
will give you almost the same API, but plumbs the routing into your app for you.