Skip to content

yew-router silently strips trailing slashes, causing surprising relative-path behavior #4098

@Madoshakalaka

Description

@Madoshakalaka

Problem

yew-router strips trailing slashes from both route patterns and incoming pathnames before matching. This means /settings and /settings/ always resolve to the same route variant and render the same component.

However, the browser resolves relative paths differently depending on whether the URL has a trailing slash:

URL in address bar Relative ref ./banner.jpg resolves to
/settings /banner.jpg
/settings/ /settings/banner.jpg

Because yew-router renders the same component for both, a component that uses relative asset paths will behave correctly for one URL but break for the other.

Steps To Reproduce

  1. Define a route with a trailing slash:
#[derive(Clone, Routable, PartialEq)]
enum MainRoute {
    #[at("/news")]
    News,
    #[at("/settings/")]
    Settings,
}
  1. In the Settings component, reference a relative asset like ./banner.jpg, expecting it to resolve to /settings/banner.jpg
  2. Navigate to /settings (no trailing slash)
  3. The component renders, but ./banner.jpg resolves to /banner.jpg instead of /settings/banner.jpg

Note: defining both #[at("/settings")] and #[at("/settings/")] in the same enum panics at router construction due to duplicate insertion (both are stripped to /settings).

Expected behavior

One of:

  1. Stop stripping trailing slashes. /settings and /settings/ become distinct routes. Most correct from a URL semantics standpoint but is a breaking change.
  2. Canonical redirect. When a route is defined as /settings/ and the user navigates to /settings, automatically redirect to /settings/ so relative-path resolution is consistent.
  3. Keep current behavior, document the caveat. Recommend absolute paths in routed components.

Environment:

Questionnaire

  • I'm interested in fixing this myself but don't know where to start
  • I would like to fix and I have a solution
  • I don't have time to fix this right now, but maybe later

Context

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions