-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: app-router prefetch crash when an invalid URL is passed to Link (#…
…66755) Closes [#66650](#66650) Closes NEXT-3520 ### What? - Make Link not throw during prefetch if it received an invalid `href` (see [#66650](#66650)) - Throw in dev mode if an invalid link was passed to `router.prefetch` -- this matches current prod behavior - (previously, we'd immediately exit out of `router.prefetch`, so the user would see no indication that this'd fail in prod) ### Why? If an invalid URL was passed to `<Link>`, the whole app would crash and show "A client-side exception occurred". A failed prefetch should not bring down the whole app. Note that This preserves the current behavior of explicit `router.prefetch(url)` throwing an error if `url` is invalid. We may want to adjust this in the future, but that could be considered a breaking change, so I'm leaving it out for now. This only affects `Link`, which was intended to catch any errors thrown from `router.prefetch`, but that bit was accidentally broken.
- Loading branch information
1 parent
62e8c9d
commit 0fee50e
Showing
8 changed files
with
106 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use client' | ||
|
||
import { useEffect } from 'react' | ||
import { useState } from 'react' | ||
|
||
export function Delay({ duration = 500, children }) { | ||
const [isVisible, setIsVisible] = useState(false) | ||
useEffect(() => { | ||
const timeout = setTimeout(() => setIsVisible(true), duration) | ||
return () => clearTimeout(timeout) | ||
}, [duration]) | ||
|
||
if (!isVisible) return null | ||
return <>{children}</> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
'use client' | ||
export default function Error() { | ||
return <h1>A prefetch threw an error</h1> | ||
} |
16 changes: 16 additions & 0 deletions
16
test/e2e/app-dir/app-prefetch/app/invalid-url/from-link/page.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import Link from 'next/link' | ||
import { INVALID_URL } from '../invalid-url' | ||
import { Delay } from '../delay' | ||
|
||
export const dynamic = 'force-dynamic' | ||
|
||
export default function Page() { | ||
return ( | ||
<> | ||
<Link href={INVALID_URL}>invalid link</Link> | ||
<Delay> | ||
<h1>Hello, world!</h1> | ||
</Delay> | ||
</> | ||
) | ||
} |
20 changes: 20 additions & 0 deletions
20
test/e2e/app-dir/app-prefetch/app/invalid-url/from-router-prefetch/page.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
'use client' | ||
import { useEffect } from 'react' | ||
import { INVALID_URL } from '../invalid-url' | ||
import { Delay } from '../delay' | ||
import { useRouter } from 'next/navigation' | ||
|
||
export const dynamic = 'force-dynamic' | ||
|
||
export default function Page() { | ||
const router = useRouter() | ||
useEffect(() => { | ||
router.prefetch(INVALID_URL) | ||
}, [router]) | ||
|
||
return ( | ||
<Delay> | ||
<h1>Hello, world!</h1> | ||
</Delay> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// We need a URL that reliably fails `new URL(url, window.location) | ||
// This only fails if `window.location` starts with `https://`: | ||
// | ||
// const invalidUrl = 'http:' | ||
// | ||
// because `new URL('http:', 'http://localhost:3000')` works fine. | ||
// So better to pick something that's always invalid | ||
export const INVALID_URL = '///' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters