diff --git a/packages/next/client/components/app-router.tsx b/packages/next/client/components/app-router.tsx index ef13e39f6021d01..9a9d1284222a079 100644 --- a/packages/next/client/components/app-router.tsx +++ b/packages/next/client/components/app-router.tsx @@ -20,6 +20,7 @@ import { ACTION_REFRESH, ACTION_RESTORE, ACTION_SERVER_PATCH, + createHrefFromUrl, reducer, } from './reducer' import { @@ -132,10 +133,11 @@ function Router({ pushRef: { pendingPush: false, mpaNavigation: false }, focusAndScrollRef: { apply: false }, canonicalUrl: - initialCanonicalUrl + - // Hash is read as the initial value for canonicalUrl in the browser - // This is safe to do as canonicalUrl can't be rendered, it's only used to control the history updates the useEffect further down. - (typeof window !== 'undefined' ? window.location.hash : ''), + // location.href is read as the initial value for canonicalUrl in the browser + // This is safe to do as canonicalUrl can't be rendered, it's only used to control the history updates in the useEffect further down in this file. + typeof window !== 'undefined' + ? createHrefFromUrl(new URL(window.location.href)) + : initialCanonicalUrl, } }, [children, initialCanonicalUrl, initialTree]) const [ diff --git a/packages/next/client/components/reducer.ts b/packages/next/client/components/reducer.ts index ad4aad58119b07e..998b0ee4baa1df6 100644 --- a/packages/next/client/components/reducer.ts +++ b/packages/next/client/components/reducer.ts @@ -43,7 +43,7 @@ function readRecordValue(thenable: any) { } } -function createHrefFromUrl(url: URL): string { +export function createHrefFromUrl(url: URL): string { return url.pathname + url.search + url.hash } diff --git a/test/e2e/app-dir/app-static.test.ts b/test/e2e/app-dir/app-static.test.ts index 4d256d73ea5ac87..21c8dd59da14575 100644 --- a/test/e2e/app-dir/app-static.test.ts +++ b/test/e2e/app-dir/app-static.test.ts @@ -4,7 +4,7 @@ import { promisify } from 'util' import path, { join } from 'path' import { createNext, FileRef } from 'e2e-utils' import { NextInstance } from 'test/lib/next-modes/base' -import { check, fetchViaHTTP, normalizeRegEx } from 'next-test-utils' +import { check, fetchViaHTTP, normalizeRegEx, waitFor } from 'next-test-utils' import webdriver from 'next-webdriver' const glob = promisify(globOrig) @@ -452,5 +452,17 @@ describe('app-dir static/dynamic handling', () => { ) }) } + + it('should keep querystring on static page', async () => { + const browser = await webdriver(next.url, '/blog/tim?message=hello-world') + const checkUrl = async () => + expect(await browser.url()).toBe( + next.url + '/blog/tim?message=hello-world' + ) + + checkUrl() + await waitFor(1000) + checkUrl() + }) }) })