### What & Why
Previously when rendering the root `/_not-found` in production, we'll always override the parallel routes component children with not-found component, this will break the navigation in build mode from root 404 `/_not-found` path.
### How
The new solution is to change the root `/_not-found` rendering strategy. Previously the loader tree of `/_not-found` look like this
```js
['',
{
children: ['not-found', {}, {}]
},
{ layout: ..., 'not-found': ...}
]
```
it's not a pretty valid tree, which could lead to problems during rendering.
New solution is to change the children to render a page, but the page content is `not-found.js` component. The new tree of root not-found will look like
```js
['',
{
children: ['__PAGE__', {}, {
page: ... // same as root 'not-found'
}]
},
{ layout: ..., 'not-found': ...}
]
```
This change could fix the navigation on the root not-found page.
Fixes#52264
### 🧐 What's in there?
This is another attempt to allow testing server-only code with Jest.
### 🧪 How to test?
There's an integration tests which can be triggered with `pnpm testheadless server-only`
Here is a more comprehensive setup:
<details>
<summary><code>app/lib/index.ts</code></summary>
```ts
import 'server-only'
export function add(num1: number, num2: number) {
return num1 + num2
}
```
</details>
<details>
<summary><code>app/lib/index.test.ts</code></summary>
```ts
import { add } from '.'
it('adds two numbers', () => {
expect(add(1, 3)).toEqual(4)
})
```
</details>
<details>
<summary><code>app/client-component.tsx</code></summary>
```ts
'use client'
import { useState } from 'react'
export default function ClientComponent() {
const [text, setText] = useState('not clicked yet')
return <button onClick={() => setText('clicked!')}>{text}</button>
}
```
</details>
<details>
<summary><code>app/client-component.test.tsx</code></summary>
```ts
import { fireEvent, render, screen } from '@testing-library/react'
import ClientComponent from './client-component'
it('can be clicked', async () => {
render(<ClientComponent />)
const button = screen.getByRole('button')
expect(button).toHaveTextContent('not clicked yet')
await fireEvent.click(button)
expect(button).toHaveTextContent('clicked!')
})
```
</details>
<details>
<summary><code>app/server-component.tsx</code></summary>
```ts
import { add } from '@/lib'
export default function ServerComponent({ a, b }: { a: number; b: number }) {
return (
<code role="comment">
{a} + {b} = {add(a, b)}
</code>
)
}
```
</details>
<details>
<summary><code>app/server-component.test.tsx</code></summary>
```ts
import { render, screen } from '@testing-library/react'
import ServerComponent from './server-component'
it('renders', () => {
render(<ServerComponent a={2} b={3} />)
expect(screen.getByRole('comment')).toHaveTextContent('2 + 3 = 5')
})
```
</details>
<details>
<summary><code>app/page.tsx</code></summary>
```ts
import Link from 'next/link'
import ClientComponent from './client-component'
import ServerComponent from './server-component'
export default function Page() {
return (
<>
<h1>Hello World</h1>
<Link href="/dave">Dave?</Link>
<p>
<ClientComponent />
</p>
<p>
<ServerComponent a={5} b={2} />
</p>
</>
)
}
```
</details>
<details>
<summary><code>app/page.test.tsx</code></summary>
```ts
import { render, screen } from '@testing-library/react'
import Page from './page'
it('greets', () => {
render(<Page />)
expect(screen.getByRole('link')).toHaveTextContent('Dave?')
expect(screen.getByRole('heading')).toHaveTextContent('Hello World')
expect(screen.getByRole('button')).toHaveTextContent('not clicked yet')
expect(screen.getByRole('comment')).toHaveTextContent('5 + 2 = 7')
})
```
</details>
<details>
<summary><code>app/[blog]/page.tsx</code></summary>
```ts
import { Metadata } from 'next'
import Link from 'next/link'
type Props = {
params: { blog: string }
}
export async function generateMetadata({
params: { blog: title },
}: Props): Promise<Metadata> {
return { title, description: `A blog post about ${title}` }
}
export default function Page({ params }: Props) {
return (
<>
<div>
<Link href="/">Back</Link>
</div>
<h1>All about {params.blog}</h1>
</>
)
}
```
</details>
<details>
<summary><code>app/[blog]/page.test.tsx</code></summary>
```ts
import { render, screen } from '@testing-library/react'
import Page from './page'
it('has the appropriate title', () => {
const title = 'Jane'
render(<Page params={{ blog: title }} />)
expect(screen.getByRole('heading')).toHaveTextContent(`All about ${title}`)
expect(screen.getByRole('link')).toHaveTextContent('Back')
})
```
</details>
<details>
<summary><code>app/layout.tsx</code></summary>
```ts
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
```
</details>
<details>
<summary><code>jest.config.js</code></summary>
```ts
const nextJest = require('next/jest')
const createJestConfig = nextJest({ dir: './' })
module.exports = createJestConfig({
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
})
```
</details>
<details>
<summary><code>package.json</code></summary>
```ts
{
"name": "rsc-test",
"version": "0.0.0",
"private": true,
"scripts": {
"test": "jest"
},
"devDependencies": {
"@testing-library/jest-dom": "latest"
}
}
```
</details>
<details>
<summary><code>test-setup.ts</code></summary>
```ts
import '@testing-library/jest-dom'
```
</details>
The app should run and all test should pass.
### ❗ Notes to reviewers
#### The problem:
1. next/jest configures jest with a transformer ([jest-transformer](https://github.com/vercel/next.js/blob/canary/packages/next/src/build/swc/jest-transformer.ts)) to compile react code with next -swc
2. the transformers configures next -swc for a given environment: Server or Client, based on jest global environment
3. Based on the environment, next -swc checks for invalid usage of `import('server-only')` `“use client”`, `export const metadata` or `export async function generateMetadata`
4. Because the global test environment is either jsdom or node, the same test suite can not include both client and server components
#### Possible mitigations
*A. Using jest projects*
When configured with [multiple projects](https://jestjs.io/docs/next/configuration/#projects-arraystring--projectconfig), Jest can launch different runners with different environment. This would allow running server-only code in node and client-only code in jsdom.
However, it requires user to completely change their jest configuration. It would also require a different setup when scaffolding new app-directory project with create-next.
*B. Using doc blocks*
Jest allows changing the environment per test file [with docBlock](https://jestjs.io/docs/configuration#testenvironment-string).
However, by the time jest is invoking next -swc on a source file to transform it, this information is gone, and next -swc is still invoked with the (wrong) global environment.
The PR #52393 provides a workaround for files with `import('server-only')`, but does not allow testing pages with metadata.
*C. Always compile for node*
Our jest-transformer could always configure next -swc for server:
- pass Server-specific validations `import('server-only')` `export const metadata` or `export async function generateMetadata`
- does not complain about `"use client"`
This is what this PR is about!
Fixes#47299
Co-authored-by: Jiachi Liu <4800338+huozhi@users.noreply.github.com>
### What?
wasm-bindgen's serde deserialization is more strict to not automatically coerce non-optionable default values for the mdx configurations. Since these are required options anyway, consolidate to construct default options.
Closes WEB-1384
This adds tags for `updatedModules` (an array of relative paths to changed modules that caused the hmr update) and `page` (the path to the updated page) to the `client-hmr-latency` event.
Test Plan: Ran `next dev` in a test app, changed a source file, and observed that the `client-hmr-latency` span in `.next/trace` has correct `page` and `updatedModules` tags.
### What?
When navigating to a new page with fixed or sticky positioned element as the first element, we were bailing on scroll to top behavior, which often isn't expected.
### Why?
Currently, we decide to bail on scroll to top behavior on navigation if the content that is swapped into view is visible within the viewport. Since fixed/sticky positioned elements are often intended to be relative to the current viewport, it's most likely not the case that you'd want it to be considered in this heuristic. For example, if you were scrolled far down on a page, and you navigated to a page that makes use of a sticky header, you would not be scrolled to the top of the page because that sticky header is technically visible within the viewport.
### How?
I've updated the previous implementation that was intended to skip targeting invisible elements to also skip over fixed or sticky elements. This should help by falling back to the next level of the layout tree to determine which element to scroll to.
I've deleted the `// TODO-APP` comments as I couldn't think of a scenario in which we'd need a global scrollTop handler -- if we've bailed on every element up the tree, it's likely the page wasn't scrollable.
Some additional considerations:
- Is the warning helpful or annoying?
- Is the parallel route trade-off an acceptable one? (ie, a parallel modal slot might not be considered in the content visibility check unless if it’s fixed positioned)
Closes NEXT-1393
Fixes#47475
### What?
Skip logging `/404` for pages routes in `next build` when app router root not-found is present
### Why?
When app router's root not-found is used it can cover all the not found cases, and for static rendering it can already replace the `404.html`. So in the tree view we don't need to log the pages `/404` when those cases are covered by app router.
`getEntryKey` had some logic to remove `children` if it was part of the entry (originally it was intended to fix an issue with parallel slots that were used in place of a page, but wasn't working as intended). However, this breaks pages that are named `children`.
Updating this again to implement what I think was the intended behavior in 4900fa21b0 which is to point to the correct entry when a parallel slot is used in place of a page component.
- x-ref: #52362
Closes NEXT-1514
Fixes#53072
Followup on the https://github.com/vercel/next.js/pull/52520. The enhancements:
1. Both `fetch` and `http(s)` APIs are intercepted in the testmode.
2. The loopback mode that would allow the test-side to use any fetch-mocking library of their choice.
Partial fix for #54012: do not generate a blur image in the image loader when the image is detected to be animated, rather than returning the *entire* animated image as the blur image.
This PR changes the internal `createActionProxy` util from a default
export to a named export, as the default export could be problematic if
it's built without the "esModuleInterop" step.
---------
Co-authored-by: Balázs Orbán <info@balazsorban.com>
ensure `next` is the dependency of third-parties package so turbo will
build next first then `@next/third-parties` to avoid type failing
---------
Co-authored-by: JJ Kasper <jj@jjsweb.site>
### What?
This PR makes it easier to use Next.js with IPv6 hostnames such as `::1` and `::`.
### How?
It does so by removing rewrites from `localhost` to `127.0.0.1` introduced in #52492. It also fixes the issue where Next.js tries to fetch something like `http://::1:3000` when `--hostname` is `::1` as it is not a valid URL (browsers' `URL` class throws an error when constructed with such hosts). It also fixes `NextURL` so that it doesn't accept `http://::1:3000` but refuse `http://[::1]:3000`. It also changes `next/src/server/lib/setup-server-worker.ts` so that it uses the server's `address` method to retrieve the host instead of our provided `opts.hostname`, ensuring that no matter what `opts.hostname` is we will always get the correct one.
### Note
I've verified that `next dev`, `next start` and `node .next/standalone/server.js` work with IPv6 hostnames (such as `::` and `::1`), IPv4 hostnames (such as `127.0.0.1`, `0.0.0.0`) and `localhost` - and with any of these hostnames fetching to `localhost` also works. Server Actions and middleware have no problems as well.
This also removes `.next/standalone/server.js`'s logging as we now use `start-server`'s logging to avoid duplicates. `start-server`'s logging has also been updated to report the actual hostname.
![image](https://github.com/vercel/next.js/assets/75556609/cefa5f23-ff09-4cef-a055-13eea7c11d89)
![image](https://github.com/vercel/next.js/assets/75556609/619e82ce-45d9-47b7-8644-f4ad083429db)
The above pictures also demonstrate using Server Actions with Next.js after this PR.
![image](https://github.com/vercel/next.js/assets/75556609/3d4166e9-f950-4390-bde9-af2547658148)
Fixes#53171Fixes#49578
Closes NEXT-1510
Co-authored-by: Tim Neutkens <6324199+timneutkens@users.noreply.github.com>
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
`expect` is an unsupported header for undici: c83b084879/lib/core/request.js (L354) -- this filters it out so that the API routes don't throw an internal server error if that header is included.
Also added a test case for the previously submitted PR that was added for `content-length: 0`
- x-ref: #53843Fixes#53822 (erroneously closed by a content-length issue being fixed)
### What?
We change the not-found rendering strategy to the origin one which recovers the not found error from the flight data, and hit the error boundary to display the closet not found component.
For parallel `@slot` we shouldn't pass down the not-found boundary, the boundary is only for `@children`.
### Why?
We're having a lot of not-found matching issues that manually searching for not found and layout won't be accurate as we have various scenarios like `(group)` routes, dynamic routes, etc.
### How?
Only render html with empty body so that the error can recover from flight and render the proper not-found component during hydration.
One change for metadata is that we need to get the "not-found" metadata in the initial render, so we'll catch the not-found error once there first and start render the "not-found" metadata and put it in the flight data. Then when it recovers it's still preserved.
Fixes#53694
Adds support for base64-encoded `placeholder`. Enables using placeholders without the "blur" effect.
Fixes#47639
- [x] Add support for DataURL placeholder
- [x] Add tests
- [x] Update docs
Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
Sharp by default spawns #cpu_cores threads to process images which could lead to large memory consumption. This PR caps the `concurrency` value especially on dev.
Locally I see a small memory improvement (10~20 MB) from this, but it will mostly affect long-running servers.
Related: https://github.com/lovell/sharp/issues/2607
Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
### What?
Updates the new `entrypoint.changed()` method to signal whether the server or client assets changed. Now, a `{ changed: 'server' | 'client' | 'both' }` will value will be yielded by the subscription.
### Why?
So that client-only changes can be handled differently than server-only changes.
### How?
We just needed to track the server and client output assets separately, so that we can detect changes to either individually. It's difficult to tell what `Vc` change triggered a recomputation on the Rust side (I'd have to involve mutable `State` into the Vc), and it's also hard to re-emit a duplicate value (eg, if a client change follows a client change, we need 2 emits). Instead, I tie the two different `server_changed()` and `client_changed()` functions into a single enum on the TS side.
Depends on https://github.com/vercel/next.js/pull/53809, since I don't want to introduce merge conflicts while Tobias is on vacation.
This is an improvement for twitter card, if there's image present we could use `summary_large_image` to make the twitter card look better instead of using `summary` by default, so that users could benefit from the large image card display on twitter
### What?
#51883:
> Node.js sets stdout to non-blocking by default, rust expects it to be blocking
>
> so when logging a lot of data, it can happen that rust receives an error while writing causing it to panic, the error is just that the resource is temporarily unavailable, but rust doesn't handle this case
>
> See https://github.com/napi-rs/napi-rs/issues/1630
### Why?
### How?
This moves the work done in #51883 into the `loadBindings` function used by both next-api and next-dev.
## For Contributors
### Improving Documentation
- [x] Run `pnpm prettier-fix` to fix formatting issues before opening the PR.
- [x] Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide
### What?
Add instructions for using `bun/bunx` where relevant. I only added mentions where npm/yarn/pnpm were all already listed.
### Why
Bun can be used as a runtime-agnostic [package manager](https://bun.sh/package-manager) and script runner in any project with a `package.json`.
(Sorry, I probably should have consolidated this with https://github.com/vercel/next.js/pull/53467)
Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
fixes https://github.com/vercel/next.js/issues/53822
PR https://github.com/vercel/next.js/pull/53368 introduced a regression causing fetch with custom headers to fail in safari.
There are known issues with uncidi when a content-length: 0 header exists.
When performing a custom fetch in safari, this header is present.
When performing a custom fetch in chrome, this header is not present.
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
This normalizes the backslash for windows users who accidentally use `\` in the request paths instead of the expected `/`.
For example, in https://github.com/nodejs/nodejs.org/pull/5617 the slash was hardcoded for split that caused the backlash to remain the the `getStaticPaths()` result.
- Fixes#51225
Closes#48479.
Couldn't find the source for the Next.js beta docs, so I didn't add documentation.
Co-authored-by: Jiachi Liu <4800338+huozhi@users.noreply.github.com>
This is a follow-up to log both conflicting paths & a link to route group docs, which I believe is the only scenario someone could trigger this
- https://github.com/vercel/next.js/pull/53752
While running our `test/integration/middleware-src` test suite across
systems, noticed this behaved inconsistently due to us relying on the
order the filesystem ordered duplicates e.g. `middleware.ts` and
`middleware.js`.
Considering we already have a loud warning for this duplicate this adds
consistency across systems by ensuring these are sorted per our
pageExtensions order which is `ts` takes priority over `js` by default.
An additional test case was not added as the above mentioned suite
covers this but was verified as passing on one of the systems (mac OS)
where it was not previously.