preactjs / preact-iso

Isomorphic utilities for Preact
MIT License
56 stars 6 forks source link

Restrict routing to a `base` path #34

Open dero opened 1 month ago

dero commented 1 month ago

Use case: Application is served on domain.com/app. Static links like domain.com/contact should not be handled by the router.

I was unable to find a satisfactory solution to restrict the preact-iso router to only be active on a predefined base path and not affect the rest of the links on the site. We embed a Preact app on some pages of our otherwise static site and we need routing to work within the app. However, we also need all existing links to trigger regular browser navigation.

Any advice? Is this something preact-iso would need to add explicit support for?

rschristian commented 1 month ago

We don't support base paths, but you could create a link component pretty easily to do this. For example:

function Link({ path, children, ...props }) {
    const internal = path.startsWith('/app');
    return <a href={path} target={internal ? null : '_top'} {...props}>{children}</a>;
}

We won't intercept links if the target isn't _self, which is the default.

dero commented 1 month ago

@rschristian That's a nice idea. Thank you, will do.

This might possibly be a useful addition to the main README?

rschristian commented 1 month ago

I agree -- PRs certainly welcome, else, I can take a look later this week maybe.

dero commented 1 month ago

@rschristian It just occurred to me that your solution won't really help us.

Since we add our Preact app as an "island", we don't really control any outside links. Meaning that those will be rendered as standard markup, e.g. <a href="/">Home</a>.

Right now my crude solution is to define a default route that will catch all routes outside of the ones /app expects, then useEffect to run window.location.reload();. This forces the browser to reload the page at the expected target URL, but it's an ugly solution.

rschristian commented 1 month ago

Yeah I wouldn't do that.

Patch the library if you need opt-in SPA routing, just insert a condition here.

pgegenfurtner commented 4 weeks ago

I'm facing the same challenge at the moment. @dero did you create a patch or found another solution? Thanks!

dero commented 3 weeks ago

did you create a patch or found another solution?

@pgegenfurtner I'm not very interested in patching the package myself as I don't want to maintain a patched package.

We will likely be looking for another routing solution soon, one that supports base paths out of the box. I'm kind of surprised that preact-iso doesn't support this use case, but it is what it is.

rschristian commented 3 weeks ago

There shouldn't be much to maintain, you'd just use something like patch-package.

That being said, I don't think we're going to support this type of usage anytime soon, so I'll close this on out. Hope you find something that fits your needs better.

Edit: On second though, reopening. If someone wants to contribute it they can, but it won't be a priority for me at the moment.

rschristian commented 3 weeks ago

Would <LocationProvider basePath="..."> (prop name still tbd) suffice? There can be multiple routers per app, as sub-routers are supported, so I don't love the idea of putting it on the router as I don't think you'd ever want multiple base paths? At least, I can't think of a reason for it.

pgegenfurtner commented 3 weeks ago

That would sound great for my use case.

dero commented 3 weeks ago

Would (prop name still tbd) suffice?

Yes, that would suffice for our use case. And I imagine people who'd need multiple base paths can instantiate multiple "app islands" on a single page, each with its own LocationProvider.

rschristian commented 3 weeks ago

On second thought, are base paths/routes necessary? I'd rather avoid supporting them if possible, they bring a fair bit of complexity.

I'm thinking something like <LocationProvider limit={string | regex}> instead, bailing out of our link detection if the href of the link doesn't match. For the initial example, that'd be used like this: <LocationProvider limit="/app">. Any link that doesn't start with /app is ignored & passed through preact-iso.

dero commented 3 weeks ago

@rschristian Complexity as in having to resolve link targets to absolute paths?

I imagine a parameter that would directly match the href would be good enough in a high percentage of use cases that would make use of base paths. It would solve the initial issue in our use case, because we control all links in our Preact app and we can ensure that all start with /app.

rschristian commented 3 weeks ago

Complexity in that we'd have to devise some system/set of patterns for how that would be resolved. Would it be prepended to links? Would router paths prepend it? How does it work with the prerendering? Is an input / transformed into ${base}/? etc.

Lot of ways to implement that and it's not something I want to poke at the moment; limiting link interception is simple though.