Skip to content
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

fix(react): improve handling of routes nested under path="/" #14821

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

mjq
Copy link
Member

@mjq mjq commented Dec 20, 2024

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:

<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! 🙌)


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

if (basename + branch.pathname === location.pathname) {

became

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, 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!

mjq added 2 commits December 20, 2024 16:05
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.
Comment on lines 429 to +430
const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`;
pathBuilder += newPath;
pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath);
Copy link
Member Author

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.)

@mjq mjq marked this pull request as ready for review December 20, 2024 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant