Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: Enable newNextLinkBehavior #41459

Merged
merged 13 commits into from Oct 18, 2022
  •  
  •  
  •  
24 changes: 24 additions & 0 deletions docs/advanced-features/codemods.md
Expand Up @@ -19,6 +19,30 @@ Codemods are transformations that run on your codebase programmatically. This al

## Next.js 13

### `new-link`

Safely removes `<a>` from `next/link` or adds `legacyBehavior` prop.

For example:

```jsx
export default function Page() {
return (
<Link href="/about">
<a>About Us</a>
</Link>
)
}
```

Transforms into:

```jsx
export default function Page() {
return <Link href="/about">About Us</Link>
}
```

### `next-image-to-legacy-image`

Safely migrates existing Next.js 10, 11, 12 applications importing `next/image` to the renamed `next/legacy/image` import in Next.js 13.
Expand Down
4 changes: 2 additions & 2 deletions docs/advanced-features/i18n-routing.md
Expand Up @@ -233,7 +233,7 @@ import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/another" locale="fr">
<a>To /fr/another</a>
To /fr/another
</Link>
)
}
Expand Down Expand Up @@ -279,7 +279,7 @@ import Link from 'next/link'
export default function IndexPage(props) {
return (
<Link href="/fr/another" locale={false}>
<a>To /fr/another</a>
To /fr/another
</Link>
)
}
Expand Down
4 changes: 1 addition & 3 deletions docs/api-reference/next.config.js/basepath.md
Expand Up @@ -35,9 +35,7 @@ For example, using `/about` will automatically become `/docs/about` when `basePa
export default function HomePage() {
return (
<>
<Link href="/about">
<a>About Page</a>
</Link>
<Link href="/about">About Page</Link>
</>
)
}
Expand Down
46 changes: 28 additions & 18 deletions docs/api-reference/next/link.md
Expand Up @@ -31,19 +31,13 @@ function Home() {
return (
<ul>
<li>
<Link href="/">
<a>Home</a>
</Link>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">
<a>About Us</a>
</Link>
<Link href="/about">About Us</Link>
</li>
<li>
<Link href="/blog/hello-world">
<a>Blog Post</a>
</Link>
<Link href="/blog/hello-world">Blog Post</Link>
</li>
</ul>
)
Expand All @@ -56,6 +50,7 @@ export default Home

- `href` - The path or URL to navigate to. This is the only required prop. It can also be an object, see [example here](/docs/api-reference/next/link.md#with-url-object)
- `as` - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes).
- [`legacyBehavior`](#if-the-child-is-a-tag) - Changes behavior so that child must be `<a>`. Defaults to `false`.
- [`passHref`](#if-the-child-is-a-custom-component-that-wraps-an-a-tag) - Forces `Link` to send the `href` property to its child. Defaults to `false`
- `prefetch` - Prefetch the page in the background. Defaults to `true`. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing `prefetch={false}`. When `prefetch` is set to `false`, prefetching will still occur on hover. Pages using [Static Generation](/docs/basic-features/data-fetching/get-static-props.md) will preload `JSON` files with the data for faster page transitions. Prefetching is only enabled in production.
- [`replace`](#replace-the-url-instead-of-push) - Replace the current `history` state instead of adding a new url into the stack. Defaults to `false`
Expand All @@ -78,7 +73,7 @@ function Posts({ posts }) {
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
<a>{post.title}</a>
{post.title}
</Link>
</li>
))}
Expand All @@ -89,6 +84,22 @@ function Posts({ posts }) {
export default Posts
```

## If the child is `<a>` tag

```jsx
import Link from 'next/link'

function Legacy() {
return (
<Link href="/about" legacyBehavior>
<a>About Us</a>
</Link>
)
}

export default Legacy
```

## If the child is a custom component that wraps an `<a>` tag

If the child of `Link` is a custom component that wraps an `<a>` tag, you must add `passHref` to `Link`. This is necessary if you’re using libraries like [styled-components](https://styled-components.com/). Without this, the `<a>` tag will not have the `href` attribute, which hurts your site's accessibility and might affect SEO. If you're using [ESLint](/docs/basic-features/eslint.md#eslint-plugin), there is a built-in rule `next/link-passhref` to ensure correct usage of `passHref`.
Expand All @@ -103,9 +114,8 @@ const RedLink = styled.a`
`

function NavLink({ href, name }) {
// Must add passHref to Link
return (
<Link href={href} passHref>
<Link href={href} passHref legacyBehavior>
<RedLink>{name}</RedLink>
</Link>
)
Expand All @@ -119,7 +129,7 @@ export default NavLink

## If the child is a functional component

If the child of `Link` is a functional component, in addition to using `passHref`, you must wrap the component in [`React.forwardRef`](https://reactjs.org/docs/react-api.html#reactforwardref):
If the child of `Link` is a functional component, in addition to using `passHref` and `legacyBehavior`, you must wrap the component in [`React.forwardRef`](https://reactjs.org/docs/react-api.html#reactforwardref):

```jsx
import Link from 'next/link'
Expand All @@ -136,7 +146,7 @@ const MyButton = React.forwardRef(({ onClick, href }, ref) => {

function Home() {
return (
<Link href="/about" passHref>
<Link href="/about" passHref legacyBehavior>
<MyButton />
</Link>
)
Expand All @@ -162,7 +172,7 @@ function Home() {
query: { name: 'test' },
}}
>
<a>About us</a>
About us
</Link>
</li>
<li>
Expand All @@ -172,7 +182,7 @@ function Home() {
query: { slug: 'my-post' },
}}
>
<a>Blog Post</a>
Blog Post
</Link>
</li>
</ul>
Expand All @@ -195,7 +205,7 @@ The default behavior of the `Link` component is to `push` a new URL into the `hi

```jsx
<Link href="/about" replace>
<a>About us</a>
About us
</Link>
```

Expand All @@ -205,6 +215,6 @@ The default behavior of `Link` is to scroll to the top of the page. When there i

```jsx
<Link href="/#hashid" scroll={false}>
<a>Disables scrolling to the top</a>
Disables scrolling to the top
</Link>
```
6 changes: 1 addition & 5 deletions docs/api-reference/next/router.md
Expand Up @@ -156,11 +156,7 @@ export default function Page(props) {
<h1>Page: {router.query.slug}</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase count</button>
<Link href="/one">
<a>one</a>
</Link> <Link href="/two">
<a>two</a>
</Link>
<Link href="/one">one</Link> <Link href="/two">two</Link>
</div>
)
}
Expand Down
8 changes: 2 additions & 6 deletions docs/migrating/from-gatsby.md
Expand Up @@ -78,15 +78,11 @@ export default function Home() {
import Link from 'next/link'

export default function Home() {
return (
<Link href="/blog">
<a>blog</a>
</Link>
)
return <Link href="/blog">blog</Link>
}
```

Update any import statements, switch `to` to `href`, and add an `<a>` tag as a child of the element.
Update any import statements, switch `to` to `href`.

## Data Fetching

Expand Down
2 changes: 1 addition & 1 deletion docs/migrating/from-react-router.md
Expand Up @@ -34,7 +34,7 @@ import Link from 'next/link'
export default function App() {
return (
<Link href="/about">
<a>About</a>
About
</Link>
)
}
Expand Down
10 changes: 3 additions & 7 deletions docs/routing/dynamic-routes.md
Expand Up @@ -63,18 +63,14 @@ function Home() {
return (
<ul>
<li>
<Link href="/post/abc">
<a>Go to pages/post/[pid].js</a>
</Link>
<Link href="/post/abc">Go to pages/post/[pid].js</Link>
</li>
<li>
<Link href="/post/abc?foo=bar">
<a>Also goes to pages/post/[pid].js</a>
</Link>
<Link href="/post/abc?foo=bar">Also goes to pages/post/[pid].js</Link>
</li>
<li>
<Link href="/post/abc/a-comment">
<a>Go to pages/post/[pid]/[comment].js</a>
Go to pages/post/[pid]/[comment].js
</Link>
</li>
</ul>
Expand Down
16 changes: 5 additions & 11 deletions docs/routing/introduction.md
Expand Up @@ -47,19 +47,13 @@ function Home() {
return (
<ul>
<li>
<Link href="/">
<a>Home</a>
</Link>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">
<a>About Us</a>
</Link>
<Link href="/about">About Us</Link>
</li>
<li>
<Link href="/blog/hello-world">
<a>Blog Post</a>
</Link>
<Link href="/blog/hello-world">Blog Post</Link>
</li>
</ul>
)
Expand Down Expand Up @@ -89,7 +83,7 @@ function Posts({ posts }) {
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
<a>{post.title}</a>
{post.title}
</Link>
</li>
))}
Expand Down Expand Up @@ -118,7 +112,7 @@ function Posts({ posts }) {
query: { slug: post.slug },
}}
>
<a>{post.title}</a>
{post.title}
</Link>
</li>
))}
Expand Down
8 changes: 2 additions & 6 deletions docs/testing.md
Expand Up @@ -66,9 +66,7 @@ import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
<Link href="/about">About</Link>
</nav>
)
}
Expand Down Expand Up @@ -183,9 +181,7 @@ import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
<Link href="/about">About</Link>
</nav>
)
}
Expand Down
2 changes: 2 additions & 0 deletions docs/upgrading.md
Expand Up @@ -11,6 +11,8 @@ The minimum Node.js version has been bumped from 12.22.0 to 14.0.0, since 12.x h
The `next/image` import was renamed to `next/legacy/image`. The `next/future/image` import was renamed to `next/image`.
A [codemod is available](/docs/advanced-features/codemods.md#next-image-to-legacy-image) to safely and automatically rename your imports.

The `next/link` child can no longer be `<a>`. Add the `legacyBehavior` prop to use the legacy behavior or remove the `<a>` to upgrade. A [codemod is available](/docs/advanced-features/codemods.md#new-link) to automatically upgrade your code.

## Upgrading to 12.2

If you were using Middleware prior to `12.2`, please see the [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide) for more information.
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/jest/jest.ts
@@ -1,7 +1,7 @@
import { loadEnvConfig } from '@next/env'
import { resolve, join } from 'path'
import loadConfig from '../../server/config'
import { NextConfigComplete } from '../../server/config-shared'
import type { NextConfigComplete } from '../../server/config-shared'
import { PHASE_TEST } from '../../shared/lib/constants'
import loadJsConfig from '../load-jsconfig'
import * as Log from '../output/log'
Expand Down
3 changes: 1 addition & 2 deletions packages/next/server/config-shared.ts
Expand Up @@ -556,8 +556,7 @@ export const defaultConfig: NextConfig = {
// TODO: change default in next major release (current v12.1.5)
legacyBrowsers: true,
browsersListForSwc: false,
// TODO: change default in next major release (current v12.1.5)
newNextLinkBehavior: false,
newNextLinkBehavior: true,
cpus: Math.max(
1,
(Number(process.env.CIRCLE_NODE_TOTAL) ||
Expand Down
4 changes: 2 additions & 2 deletions test/development/basic-basepath/hmr/pages/hmr/index.js
Expand Up @@ -2,8 +2,8 @@ import Link from 'next/link'

export default () => (
<div>
<Link href="/hmr/error-in-gip">
<a id="error-in-gip-link">Bad Page</a>
<Link href="/hmr/error-in-gip" id="error-in-gip-link">
Bad Page
</Link>
</div>
)
Expand Up @@ -4,7 +4,7 @@ export default function IndexPage() {
return (
<div>
<Link href="/about" prefetch>
<a>To About Page</a>
To About Page
</Link>
</div>
)
Expand Down
Expand Up @@ -3,9 +3,7 @@ import Link from 'next/link'
export default function NoPrefetchPage() {
return (
<div>
<Link href="/about">
<a>No prefetch</a>
</Link>
<Link href="/about">No prefetch</Link>
</div>
)
}
Expand Up @@ -4,7 +4,7 @@ export default function PrefetchFalsePage() {
return (
<div>
<Link href="/about" prefetch={false}>
<a>Prefetch set to false</a>
Prefetch set to false
</Link>
</div>
)
Expand Down
Expand Up @@ -2,8 +2,6 @@ import Link from 'next/link'

export default () => (
<div>
<Link href="/dynamic/no-chunk">
<a>No Chunk</a>
</Link>
<Link href="/dynamic/no-chunk">No Chunk</Link>
</div>
)