-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(react): improve handling of routes nested under path="/" #14821
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
Conversation
We noticed this in Sentry's `/issues/:groupId/` route, which uses SDK v8.43.0. The full route tree is complex, but the relevent parts are:
```js
<Route path="/" element={<div>root</div>}>
<Route path="/issues/:groupId/" element={<div>issues group</div>}>
<Route index element={<div>index</div>} />
</Route>
</Route>
```
If you navigate to e.g. `/issues/123`, the recorded transaction name is
`//issues/:groupId/` (notice the double slash). This is messy but doesn't have
too much of a consequence.
The worse issue is when you navigate to e.g. `/issues/123/` (note the trailing
slash), the transaction name is `/issues/123/` - it is not parameterized. This
breaks transaction grouping. On the `master` and `develop` branch of the SDK,
the transaction name is recorded as `/`. This causes the transactions to be
grouped incorrectly with the root, as well as other routes with this structure
(nested under a route with path `/`).
This commit fixes both of these issues and passes both the new tests (which reproduce the above issues) and all existing tests, but I still don't trust the change.
First, `newPath` now always has a leading slash, and I don't know how that
interacts with the other path concatenations inside `getNormalizedName`. It
feels like dealing with path concatenation should be handled in a more
systematic way.
Second, I revert a change from 3473447 where
```js
if (basename + branch.pathname === location.pathname) {
```
became
```
if (location.pathname.endsWith(basename + branch.pathname)) {
```
This is the change that difference in results between SDK versions. This will
always match when `basename` is empty, `branch.pathname` is `/`, and
`location.pathname` ends with `/` - in other words, if you have a parent route
with `path="/"`, every request ending in a slash will match it instead of the
more specific child route. This seems likely to be a wide regression in
transaction names. But, no tests failed from this change, which makes me
worried that there's some necessary behaviour that isn't covered.
| const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`; | ||
| pathBuilder += newPath; | ||
| pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath); |
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.
Originally I thought to change these lines to
const newPath = prefixWithSlash(path);
pathBuilder = trimSlash(pathBuilder) + newPath;but newPath is used in a different path concatenation further down the method and, even though no tests fail, I didn't want collateral damage. (Tests probably should have failed though - I think the path concatenation in this method could be better handled, and is under-tested.)
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.
I think we can make a refactor/cleanup once we get the tests in a better state.
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.
Thanks for the fix @mjq! I think it's safe to merge, and I agree that we need to improve tests to cover as many route declaration patterns as possible.
|
|
||
| // If the path matches the current location, return the path | ||
| if (location.pathname.endsWith(basename + branch.pathname)) { | ||
| if (trimSlash(location.pathname) === trimSlash(basename + branch.pathname)) { |
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.
I'd expect this to break descendant routes. But in the final implementation, descendant routes don't end up here. So, I believe it's safe to revert.
| const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`; | ||
| pathBuilder += newPath; | ||
| pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath); |
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.
I think we can make a refactor/cleanup once we get the tests in a better state.
|
Thanks @onurtemizkan! Going to merge in that case 👍 |
We noticed this in Sentry's `/issues/:groupId/` route, which uses SDK
v8.43.0. The full route tree is complex, but the relevant parts are:
```js
<Route path="/" element={<div>root</div>}>
<Route path="/issues/:groupId/" element={<div>issues group</div>}>
<Route index element={<div>index</div>} />
</Route>
</Route>
```
If you navigate to e.g. `/issues/123` (no trailing slash), the recorded
transaction name is `//issues/:groupId/` (notice the double slash). This
looks messy but doesn't have too much of a consequence.
The worse issue is when you navigate to e.g. `/issues/123/` (with
trailing slash), the transaction name is `/issues/123/` - it is not
parameterized. This breaks transaction grouping. On the `master` and
`develop` branch of the SDK, the transaction name is recorded as `/`.
This causes the transactions to be grouped incorrectly with the root, as
well as any other routes nested under a route with `path="/"`.
(Thanks @JoshFerge for noticing the bad data in Sentry! 🙌)
---
Note that this commit effectively reverts a change from #14304 where
```js
if (basename + branch.pathname === location.pathname) {
```
became
```js
if (location.pathname.endsWith(basename + branch.pathname)) {
```
This is the change that caused the difference in results between SDK
versions. This will always match when `basename` is empty,
`branch.pathname` is `/`, and `location.pathname` ends with `/` - in
other words, if you have a parent route with `path="/"`, every request
ending in a slash will match it instead of the more specific child
route. (Depending on how often this kind of `Route` nesting happens in
the wild, this could be a wide regression in transaction names.) But, no
tests failed from the removal of `endsWith`. @onurtemizkan, who wrote
the change in question:
> I'd expect this to break descendant routes. But in the final
> implementation, descendant routes don't end up here. So, I
> believe it's safe to revert.
We noticed this in Sentry's `/issues/:groupId/` route, which uses SDK
v8.43.0. The full route tree is complex, but the relevant parts are:
```js
<Route path="/" element={<div>root</div>}>
<Route path="/issues/:groupId/" element={<div>issues group</div>}>
<Route index element={<div>index</div>} />
</Route>
</Route>
```
If you navigate to e.g. `/issues/123` (no trailing slash), the recorded
transaction name is `//issues/:groupId/` (notice the double slash). This
looks messy but doesn't have too much of a consequence.
The worse issue is when you navigate to e.g. `/issues/123/` (with
trailing slash), the transaction name is `/issues/123/` - it is not
parameterized. This breaks transaction grouping. On the `master` and
`develop` branch of the SDK, the transaction name is recorded as `/`.
This causes the transactions to be grouped incorrectly with the root, as
well as any other routes nested under a route with `path="/"`.
(Thanks @JoshFerge for noticing the bad data in Sentry! 🙌)
---
Note that this commit effectively reverts a change from #14304 where
```js
if (basename + branch.pathname === location.pathname) {
```
became
```js
if (location.pathname.endsWith(basename + branch.pathname)) {
```
This is the change that caused the difference in results between SDK
versions. This will always match when `basename` is empty,
`branch.pathname` is `/`, and `location.pathname` ends with `/` - in
other words, if you have a parent route with `path="/"`, every request
ending in a slash will match it instead of the more specific child
route. (Depending on how often this kind of `Route` nesting happens in
the wild, this could be a wide regression in transaction names.) But, no
tests failed from the removal of `endsWith`. @onurtemizkan, who wrote
the change in question:
> I'd expect this to break descendant routes. But in the final
> implementation, descendant routes don't end up here. So, I
> believe it's safe to revert.
upgrading so we can get the fix for our transaction names in getsentry/sentry-javascript#14821 in!
upgrading so we can get the fix for our transaction names in getsentry/sentry-javascript#14821 in!
We noticed this in Sentry's
/issues/:groupId/route, which uses SDK v8.43.0. The full route tree is complex, but the relevant parts are:If you navigate to e.g.
/issues/123(no trailing slash), the recorded transaction name is//issues/:groupId/(notice the double slash). This looks messy but doesn't have too much of a consequence.The worse issue is when you navigate to e.g.
/issues/123/(with trailing slash), the transaction name is/issues/123/- it is not parameterized. This breaks transaction grouping. On themasteranddevelopbranch of the SDK, the transaction name is recorded as/. This causes the transactions to be grouped incorrectly with the root, as well as any other routes nested under a route withpath="/".(Thanks @JoshFerge for noticing the bad data in Sentry! 🙌)
This commit fixes both of these issues and passes both the new tests (which reproduce the above issues) and all existing tests, but I don't trust my changes.
I effectively revert a change from #14304 where
became
This is the change that caused the difference in results between SDK versions. This will always match when
basenameis empty,branch.pathnameis/, andlocation.pathnameends with/- in other words, if you have a parent route withpath="/", every request ending in a slash will match it instead of the more specific child route. (Depending on how often this kind ofRoutenesting happens in the wild, this could be a wide regression in transaction names.) But, no tests failed from the removal ofendsWith, which makes me worried that there's some necessary behaviour that isn't covered and would be broken by this fix. @onurtemizkan can you give some context into that change? Thanks!