[PR #421] [MERGED] fix: preserve Pages Router query arrays and hash in asPath #559

Closed
opened 2026-05-06 13:08:45 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/421
Author: @JaredStowell
Created: 3/10/2026
Status: Merged
Merged: 3/10/2026
Merged by: @james-elicx

Base: mainHead: jstowell/fix-pages-router-query-arrays-and-aspath-hash


📝 Commits (2)

  • 8e8764d Handle array query params
  • e4b2c62 Fix router query merge order

📊 Changes

5 files changed (+273 additions, -13 deletions)

View changed files

📝 packages/vinext/src/shims/router.ts (+11 -8)
📝 packages/vinext/src/utils/query.ts (+21 -5)
📝 tests/api-handler.test.ts (+19 -0)
📝 tests/e2e/pages-router/shallow-routing.spec.ts (+52 -0)
📝 tests/shims.test.ts (+170 -0)

📄 Description

Fix Pages Router state reconstruction in next/router so it matches Next.js behavior more closely:

  • preserve string[] values in router.query instead of flattening them with join(",")
  • preserve repeated search params as arrays (?tag=a&tag=b -> { tag: ["a", "b"] })
  • preserve URL fragments in router.asPath on the client (#hash is no longer dropped)

Root cause

getPathnameAndQuery() in packages/vinext/src/shims/router.ts had three corruption points:

  • SSR context arrays were converted to comma-joined strings
  • client-side dynamic route param arrays from __NEXT_DATA__.query were converted to comma-joined strings
  • repeated search params were collapsed to the last value because the client parser used scalar assignment
  • asPath was rebuilt from pathname + search, which always dropped window.location.hash

Changes

  • packages/vinext/src/shims/router.ts

    • keep SSR query arrays intact
    • keep client route param arrays intact
    • parse repeated search params with the shared addQueryParam() helper
    • merge search params over route params to preserve existing server-side precedence
    • include window.location.hash in client asPath
  • tests/shims.test.ts

    • add regression test for SSR array query preservation
    • add regression test for client route param arrays, repeated search params, and hash-preserving asPath
  • tests/e2e/pages-router/shallow-routing.spec.ts

    • add browser-level regression for repeated query params plus #hash
    • add browser-level regression for catch-all route params staying arrays

Testing

  • pnpm exec oxfmt packages/vinext/src/shims/router.ts tests/shims.test.ts tests/e2e/pages-router/shallow-routing.spec.ts
  • pnpm test tests/shims.test.ts
  • PLAYWRIGHT_PROJECT=pages-router pnpm exec playwright test tests/e2e/pages-router/shallow-routing.spec.ts
  • pnpm exec oxlint --deny-warnings packages/vinext/src/shims/router.ts tests/shims.test.ts tests/e2e/pages-router/shallow-routing.spec.ts
  • pnpm run typecheck

Notes

This PR fixes the read-side corruption in Pages Router state reconstruction. It does not change object-form navigation serialization for router.push({ query: ... }), which is a separate write-path concern.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/421 **Author:** [@JaredStowell](https://github.com/JaredStowell) **Created:** 3/10/2026 **Status:** ✅ Merged **Merged:** 3/10/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `jstowell/fix-pages-router-query-arrays-and-aspath-hash` --- ### 📝 Commits (2) - [`8e8764d`](https://github.com/cloudflare/vinext/commit/8e8764d88262bbe93380ec491cc44d5459592f06) Handle array query params - [`e4b2c62`](https://github.com/cloudflare/vinext/commit/e4b2c628428257dfecc6007dd6e44cb2c62bbab1) Fix router query merge order ### 📊 Changes **5 files changed** (+273 additions, -13 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/shims/router.ts` (+11 -8) 📝 `packages/vinext/src/utils/query.ts` (+21 -5) 📝 `tests/api-handler.test.ts` (+19 -0) 📝 `tests/e2e/pages-router/shallow-routing.spec.ts` (+52 -0) 📝 `tests/shims.test.ts` (+170 -0) </details> ### 📄 Description Fix Pages Router state reconstruction in `next/router` so it matches Next.js behavior more closely: - preserve `string[]` values in `router.query` instead of flattening them with `join(",")` - preserve repeated search params as arrays (`?tag=a&tag=b` -> `{ tag: ["a", "b"] }`) - preserve URL fragments in `router.asPath` on the client (`#hash` is no longer dropped) ## Root cause `getPathnameAndQuery()` in `packages/vinext/src/shims/router.ts` had three corruption points: - SSR context arrays were converted to comma-joined strings - client-side dynamic route param arrays from `__NEXT_DATA__.query` were converted to comma-joined strings - repeated search params were collapsed to the last value because the client parser used scalar assignment - `asPath` was rebuilt from `pathname + search`, which always dropped `window.location.hash` ## Changes - `packages/vinext/src/shims/router.ts` - keep SSR query arrays intact - keep client route param arrays intact - parse repeated search params with the shared `addQueryParam()` helper - merge search params over route params to preserve existing server-side precedence - include `window.location.hash` in client `asPath` - `tests/shims.test.ts` - add regression test for SSR array query preservation - add regression test for client route param arrays, repeated search params, and hash-preserving `asPath` - `tests/e2e/pages-router/shallow-routing.spec.ts` - add browser-level regression for repeated query params plus `#hash` - add browser-level regression for catch-all route params staying arrays ## Testing - `pnpm exec oxfmt packages/vinext/src/shims/router.ts tests/shims.test.ts tests/e2e/pages-router/shallow-routing.spec.ts` - `pnpm test tests/shims.test.ts` - `PLAYWRIGHT_PROJECT=pages-router pnpm exec playwright test tests/e2e/pages-router/shallow-routing.spec.ts` - `pnpm exec oxlint --deny-warnings packages/vinext/src/shims/router.ts tests/shims.test.ts tests/e2e/pages-router/shallow-routing.spec.ts` - `pnpm run typecheck` ## Notes This PR fixes the read-side corruption in Pages Router state reconstruction. It does not change object-form navigation serialization for `router.push({ query: ... })`, which is a separate write-path concern. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:08:45 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#559
No description provided.