Skip to content

fix: stop adding the base twice to paths nodes in navigate and useLinkState - #717

Merged
ryansolid merged 1 commit into
solidjs:nextfrom
brenelz:fix/paths-node-base
Nov 4, 2026
Merged

ryansolid merged 1 commit into
solidjs:nextfrom
brenelz:fix/paths-node-base

Conversation

@brenelz

@brenelz brenelz commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Under a base, navigate(paths.about) and useLinkState(paths.about) add the base twice. With base: "/app", navigate(paths.about) goes to /app/app/about, which matches no route, and useLinkState(paths.about) is never active or current on /app/about. Both are documented usages (navigate(paths.users(2)), and the TabLink example for useLinkState).

Root cause

A paths node already includes the base, both in its toString() and in its Symbol.for("solid.Href") brand. navigate read the brand and then passed it through route.resolvePath, which prefixes the base onto any path that starts with /. useLinkState coerced the node with String() and resolved it the same way. Under hashHistory that coercion produced the display href (#/about), so useLinkState(paths.about) was never current there either, with or without a base.

Changes

  • navigate uses a node's brand as the resolved target, without resolving it again.
  • useLinkState reads the brand when there is one and resolves plain strings as before. Plain strings stay relative to the base, as claims.spec.tsx documents, so useLinkState(() => "/about") and navigate("/about") behave as they did.

Verification

test/paths-base.spec.tsx covers navigate and useLinkState with a node under a base (memory history), with a node under hashHistory, and with both together. All four tests fail on next and pass with this change.

  • npx vitest run: 732 passed
  • npx vitest run --config vitest.config.server.ts: 105 passed
  • npm run test:types and npm run build: pass

Open

Under a base, redirect(paths.login) from a query still lands on /app/app/login. The brand puts /app/login into Location, and the client treats a single-slash Location as relative to the base, as the README documents. A raw HTTP redirect treats the same header as a full document path, so fixing this means choosing between those two rules. This PR leaves it alone. Zero-argument calls such as paths.about() return a plain string, so they also follow the base-relative string rule.

🤖 Generated with Claude Code

@changeset-bot

changeset-bot Bot commented Nov 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e29aeda

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/router Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

ryansolid pushed a commit that referenced this pull request Nov 4, 2026
With a leading slash a full path, a paths node's brand resolves to itself,
so navigate goes back to plain resolution and useLinkState only reads the
brand (hash mode's toString is the display href).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117BoWNSSgtemsSYsaX2hXE
@ryansolid
ryansolid merged commit e29aeda into solidjs:next Nov 4, 2026
4 checks passed

Copy link
Copy Markdown
Member

Landed in #718, which keeps this PR's commit. The fix grew into a broader rule: under a base, a leading-slash string is now a full path in every API, paths nodes are never resolved again, and the redirect-under-base case from the Open section is fixed as well. Thanks!


Generated by Claude Code

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.

2 participants