react-router: [v6] Link with absolute path doesn't respect basename
Version
6.0.0-alpha.2
Test Case
https://codesandbox.io/s/react-router-v6-basepath-1dcnm
Steps to reproduce
Set up <Routes basename="/something">, and inside its component tree use a link with absolute path <Link to="/path">path</Link>
Expected Behavior
Link respects basename specified in its parent Routes, and generates URL <a href="/something/path">
Actual Behavior
Link ignores basename, and generates absolute URL from website root <a href="/path">
Comment
This is the expected behaviour of basename as described in v5 docs - e.g. here, unless it was an intentional change in v6 - was it?
Looking at the code, I suspect the problem is these two lines of resolveLocation:
https://github.com/ReactTraining/react-router/blob/dev/packages/react-router/index.js#L766-L767
If toPathname starts with a slash (like in a codesandbox example above) - resolveLocation ignores fromPathname, and as the result - loses basename value that it may have contained.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 37
- Comments: 41 (4 by maintainers)
Commits related to this issue
- React Router 6 waiting for basepath fix: https://github.com/ReactTraining/react-router/issues/7216 — committed to benneq/irgendwas-mit-hardware by benneq 4 years ago
Fixed in https://github.com/ReactTraining/react-router/pull/7462. New beta release coming this week!
@renatobenks They mean in a subdirectory, eg
foo.com/barinstead offoo.com. In previous versions of RR it’s easy to run RR out of a subdirectory; all you need to do is set thebasenamein one location. No other parts of the codebase need to be aware of the url structure. However, in v6,basenameonly works for routes but not links, requiring them to be prepended with thebasename. This means every link in the application needs knowledge of thebasenamewhich results in more complexity, verbosity, and/or tighter coupling to the base.It seems the overwhelming majority prefer the behaviour of previous versions because they’re much easier to set up with subdirectories, which a lot of people are doing. Also, it doesn’t make sense how
basenameworks for routes but not links. Either it should be a configuration that works for both or it should be completely removed.I’m only repeating what has already been discussed so apologies to all who have notifications turned on.
I would add to @levymetal example above that from my understanding, the intent behind
basenameis to support the same application deployed under different base URLs. Taking that/for/barexample above, I may have the same app deployed ashttps://example.com/foo/bar(no basepath), orhttps://example2.com/home/foo/bar(basepath/home), orhttps://example3.com/deep/route/foo/bar(basepath/deep/route).In v5 one could define appropriate
basepathvalue for these deployment (e.g. pass it down as configuration parameter), and have the app working correctly completely oblivious to the fact that it’s deployed at the root URL.In v6 the only workable approach so far seems to be passing basepath down to all components in the app, and prefixing all relevant routes/link like
<Link to={${basepath}/baz} />- which works, but it’s very noisy and looks like a step back from v5.I’m happy to PR a fix, but I was hoping to get some confirmation from react-router team here that this is indeed a bug, and/or an thumbs up on the approach to the fix outlined in my comment above
It would certainly be great to hear the devs’ thoughts regarding this issue.
basenamefunctionality has changed from v5:Some additional examples using the latest versions:
Just confirming that this issue is still valid in v6.0.0-alpha.5: https://codesandbox.io/s/react-router-v6-basepath-1dcnm
This is still a problem in the recent beta
I’m trying understand what is the reason for providing
basenameonRoutescomponent while having nobasenamesupport on(Browser)Router. Definitely not saying it’s wrong, just that I’m unable to see the use case it’s probably intended for.I would like to know what is the recommended solution/workaround when we need to deploy React app under non-root path on the server?
Explicitly prefixing all
Link/Navigatepaths in the codebase seems wrong.Bumping this since there’s been two releases since and it seems to still not be addressed. Old basename would automatically prepend it to Link paths. Preferable that would stay the same IMO.
Unless I am misunderstanding it, I think this fix causes a different issue. In an app with multiple deeply nested routes that are built via the
useRouteshooks,We see something like this:
basename = basename ? joinPaths([parentPathname, basename]) : parentPathname;Nested
useRoutesset thebasenamebased on the parent’s path name. And then when you navigate, it now uses that base name, meaning that, if I am not mistaken, a call to navigate() has absolutely no ability to ‘break out’ of the most nested route in which it is found, as it will always be relative to the context’s basenameI do agree that, in general, navigation being relative to the basename (for the purposes discussed above) is a good thing but how would you approach this scenario as it seems like a trap?
@malyzeli Yeah I’ve been through the migration docs. They don’t mention anything about the behaviour of
basenamebeing different to previous versions. Regarding the trailing slash, the docs specifically state the behaviour is the same regardless of whether the current url has a trailing slash or not so I’m unclear what this has to do with the described issue. Would you be kind enough to elaborate?Just to clarify with the most concise example I can conjure up:
The
Routewith path/bazmatches/foo/bar/bazbecause of thebasenameonRoutes. TheLinkwith the exact same path as theRouteignores thebasenameand generates an anchor to/baz. This is different to previous versions of React Router where both theRouteand theLinkwould be prepended with thebasename.If this is intentional then perhaps
basenameshould be removed altogether to remove confusion.Would anyone be able to confirm whether this is an intentional change or a bug? I’m proactively preparing a very large project for v6 and I’m a bit stuck on this - unsure whether I should expect
basenameto work as it previously did, or if I’m going to need to manually prepend thebasenameto everyLink&navigateetc.I took a similar approach that I can use unless I am missing a more proper solution. I have a usePathNavigate() which makes
/absolute to the top level basename and decided on a unix-y convention of using~/to mean ‘local to my basename’. At least to me, when I see anavigate('/foo')in the app, I like knowing its from the app root regardless of the location from which it is invoked.I confirm the problem. In a micro front architecture it is very annoying
a bump to keep the stale bot away
Yeah it isn’t working for me either. Here’s the original sandbox with the leading slash removed from
basename: https://codesandbox.io/s/react-router-v6-basepath-co3h9.<Link to="/path">still generates<a href="/path">instead of<a href="/base/path">I don’t know yet if I like this change, basically if I’ve a route with a link to another route
with react-router@5 you’d just:
and the link to “/bar” would translate to “/app/bar” as expected
now with react-router@6 it seems you need to do:
where you need to play with relative paths all the way
This is super annoying if a component is reused and displayed from different path levels, and simply impractical overall, I prefer dealing with absolute paths, they’re more explicit
The idea of course if to avoid repeating “/app” prefix over and over (in my case it would be dynamically set)
I could try to make my own
LinkanduseNavigatecomponents that will prefix “/app” to a link like “/bar”, but why doesn’t react-router@6 provides this? It seems so importantSo 👍 for this issue description
Hmm, I like using the
~/convention, but to me it’d make more sense the other way round – treating~/as the root of the nested route I’m in (as if the nested route was a Unix user with their own user folder).That would result in all my links differing from v6’s approach (absolute links starting with
/while v6 requires../../../, and relative ones starting with~/while v6 uses/, but I need a readable solution that makes sense to me, and theirs currently doesn’t).I might go with
~/as root for nested routes and/for absolute ones, from all the versions I’ve seen and tried, that reads best to me. Thanks for sharing, @labriola !While we await PR merge, I suggest we consider using custom
LinkandNavigatecomponents where we’ll add basenameexample:
The same issue is present with the
Navigatecomponent (using6.0.0-beta.0):When directly opening
http://localhost:3000/my-public-url-path/homeit works fine. But when openinghttp://localhost:3000/my-public-url-path/I get redirected tohttp://localhost:3000/home.@malyzeli
it’s been mentioned in another issue here