No description
Find a file
Tim Neutkens 489e65ed98
Rework <Link> behavior (backwards compatible) (#36436)
Fixes https://github.com/vercel/next.js/discussions/32233

⚠️ If you're looking at this PR please read the complete description including the part about incremental adoption.

## TLDR:

Official support for `<Link href="/about">About</Link>` / `<Link href="/about"><CustomComponent /></Link>` / `<Link href="/about"><strong>About</strong></Link>` where `<Link>` always renders `<a>` without edge cases where it doesn’t render `<a>`. You'll no longer have to put an empty `<a>` in `<Link>` with this enabled.

## Full context

### Changes to `<Link>`

- Added an `legacyBehavior` prop that defaults to `true` to preserve the defaults we have today, this will allow to run a codemod on existing codebases to move them to the version where `legacyBehavior` becomes `false` by default
- When using the new behavior `<Link>` always renders an `<a>` instead of having `React.cloneElement` and passing props onto a child element
- When using the new behavior props that can be passed to `<a>` can be passed to `<Link>`. Previously you could do something like `<Link href="/somewhere"><a target="_blank">Download</a></Link>` but with `<Link>` rendering `<a>` it now allows these props to be set on link. E.g. `<Link href="/somewhere" target="_blank"></Link>` / `<Link href="/somewhere" className="link"></Link>`

### Incremental Adoption / Codemod

The main reason we haven't made these changes before is that it breaks pretty much all Next.js apps, which is why I've been hesitant to make this change in the past. I've spent a bunch of time figuring out what the right approach is to rolling this out and ended up with an approach that requires existing apps to run a codemod that automatically opts their `<Link>` usage into the old behavior in order to keep the app functioning.

This codemod will auto-fix the usage where possible. For example: 

- When you have `<Link href="/about"><a>About</a></Link>` it'll auto-fix to `<Link href="/about">About</Link>`
- When you have `<Link href="/about"><a onClick={() => console.log('clicked')}>About</a></Link>` it'll auto-fix to `<Link href="/about" onClick={() => console.log('clicked')}>About</Link>`
- For cases where auto-fixing can't be applied the `legacyBehavior` prop is added. When you have `<Link href="/about"><Component /></Link>` it'll transform to `<Link href="/about" legacyBehavior><Component /></Link>` so that your app keeps functioning using the old behavior for that particular link. It's then up to the dev to move that case out of the `legacyBehavior` prop.


**This default will be changed in Next.js 13, it does not affect existing apps in Next.js 12 unless opted in via `experimental.newLinkBehavior` and running the codemod.**

Some code samples of what changed:

```jsx
const CustomComponent = () => <strong>Hello</strong>

// Legacy behavior: `<a>` has to be nested otherwise it's excluded

// Renders: <a href="/about">About</a>. `<a>` has to be nested.
<Link href="/about">
  <a>About</a>  
</Link>

// Renders: <strong onClick={nextLinkClickHandler}>Hello</strong>. No `<a>` is included.
<Link href="/about">
  <strong>Hello</strong>
</Link>


// Renders: <strong onClick={nextLinkClickHandler}>Hello</strong>. No `<a>` is included.
<Link href="/about">
  <CustomComponent />
</Link>

// --------------------------------------------------
// New behavior: `<Link>` always renders `<a>`

// Renders: <a href="/about">About</a>. `<a>` no longer has to be nested.
<Link href="/about">
  About
</Link>

// Renders: <a href="/about"><strong>Hello</strong></a>. `<a>` is included.
<Link href="/about">
  <strong>Hello</strong>
</Link>

// Renders: <a href="/about"><strong>Hello</strong></a>. `<a>` is included.
<Link href="/about">
  <CustomComponent />
</Link>
```

---


## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have helpful link attached, see `contributing.md`


Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
2022-04-25 22:01:30 +00:00
.github Update CI cache key to allow re-running only failed (#36249) 2022-04-18 19:09:51 +00:00
.vscode Additional bench tracing improvements (#29325) 2021-09-27 12:57:37 +02:00
bench Send build trace to datadog in CI (#35306) 2022-03-31 14:37:59 +02:00
docs Update usage paragraph of next/script onLoad (#36453) 2022-04-25 17:51:35 +00:00
errors Fix broken data fetching links in docs (#33766) 2022-04-22 14:03:07 +02:00
examples Grammar Changed features and API to features and it's API (#36396) 2022-04-25 13:50:17 +00:00
packages Rework <Link> behavior (backwards compatible) (#36436) 2022-04-25 22:01:30 +00:00
scripts Make setup-wasm script work for local dev (#36355) 2022-04-21 15:41:48 -05:00
test Rework <Link> behavior (backwards compatible) (#36436) 2022-04-25 22:01:30 +00:00
.alexignore Enable Alex documentation linting for docs (#26598) 2021-06-25 11:40:50 -05:00
.alexrc Add instructions to create pages directory and add an index.js file to it (#35971) 2022-04-15 14:40:37 +02:00
.eslintignore Adds web worker support to <Script /> using Partytown (#34244) 2022-03-11 22:26:46 +00:00
.eslintrc.json test: warn on substr() usage (#35499) 2022-03-24 18:35:33 -04:00
.gitattributes the way towards webpack 5 typings (#29105) 2021-09-21 19:17:16 +02:00
.gitignore Lazy-load postcss (#31762) 2021-11-25 18:41:20 +01:00
.npmrc Remove version prefix 2018-10-02 01:35:56 +02:00
.prettierignore fixes to allow lazy compilation for import() (#32441) 2021-12-14 11:33:04 +01:00
.prettierignore_staged Extract next-swc Rust code into its own package (#31635) 2021-11-21 12:59:56 +01:00
.prettierrc.json Prettier trailingComma default value to es5 since 2.0 (#14391) 2020-06-22 13:25:24 +02:00
azure-pipelines.yml Update azure config (#33999) 2022-02-04 13:42:22 -06:00
CODE_OF_CONDUCT.md updated code of conduct to v2.1 (#34208) 2022-02-10 18:11:42 -06:00
contributing.md Make setup-wasm script work for local dev (#36355) 2022-04-21 15:41:48 -05:00
jest.config.js Don't swallow test failures caused by POSIX signals (#32688) 2021-12-21 12:52:07 -06:00
lerna.json v12.1.6-canary.6 2022-04-22 08:57:41 -04:00
license.md Update license year 2022-01-13 16:02:34 +01:00
lint-staged.config.js Replace CLIEngine with ESLint (#25801) 2021-06-09 13:54:10 +02:00
package.json chore: upgrade PostCSS dependencies (#34354) 2022-04-22 13:14:29 +02:00
plopfile.js Clarify test types during scaffolding (#34638) 2022-02-21 12:09:32 -06:00
readme.md Monorepo (#5341) 2018-10-01 01:02:10 +02:00
release.js Fix labels for release sections 2021-11-21 13:11:54 +01:00
run-tests.js Continue testing react v17 with e2e tests (#35787) 2022-03-31 17:35:00 -05:00
SECURITY.md Add link to security email directly. (#33358) 2022-01-15 21:33:43 -06:00
skip-docs-change.js Update repo scripts to separate folder (#26787) 2021-07-01 13:41:27 +02:00
test-file.txt Add additional file serving tests (#12479) 2020-05-04 11:58:19 -05:00
tsconfig-tsec.json Integrate tsec into the linting process (#33746) 2022-02-24 16:59:18 -08:00
tsconfig.json Update test set-up to leverage playwright when able to (#28634) 2021-09-13 14:36:25 +02:00
tsec-exemptions.json Integrate tsec into the linting process (#33746) 2022-02-24 16:59:18 -08:00
UPGRADING.md Move upgrading guide to /docs (#10727) 2020-02-28 23:46:18 +01:00
vercel.json Silence GH Comments for Preview URLs (#18766) 2020-11-03 21:59:47 +00:00
yarn.lock chore: upgrade PostCSS dependencies (#34354) 2022-04-22 13:14:29 +02:00

Next.js

Getting Started

Visit https://nextjs.org/learn to get started with Next.js.

Documentation

Visit https://nextjs.org/docs to view the full documentation.

Who is using Next.js?

Next.js is used by the world's leading companies. Check out the Next.js Showcase to learn more.

Community

The Next.js community can be found on GitHub Discussions, where you can ask questions, voice ideas, and share your projects.

To chat with other community members you can join the Next.js Discord.

Our Code of Conduct applies to all Next.js community channels.

Contributing

Please see our contributing.md.

Good First Issues

We have a list of good first issues that contain bugs which have a relatively limited scope. This is a great place to get started, gain experience, and get familiar with our contribution process.

Authors