## What
When users specify `"type": "module"` in Next.js app, especially with
`create-next-app`, `Image` component is not working. An error
`Unsupported Server Component type: {...}` is thrown.
## Why
`next/image` API is mixing with a client component as default export and
a named export as server component. But the entry file of the API is
still CJS file, which will import the module as the object. So you'll
get `{ default, unstable_getImageProps }` when you do `import Image from
'next/image'` instead of `Image` component itself, where the CJS module
load all the exports as an object. This is expected behavior for ESM but
breaks the usage.
It only errors when you're using js extensions, if you're using
typescript, it still works. If you're using turbopack, it works in dev
mode.
This is also because webpack can't analyze the exports from CJS module
of that `next/image` entry file. Usually we can assign the default
export to the module itself, then attach other named exports onto it, so
the default export equals the `module.exports` itself. But for
`next/image` since the default export is an client component, doing that
will error with React as you cannot modify the react client reference.
Turbopack doesn't use the same way to analyze the default export, so it
doesn't have this problem.
## How
We create few ESM version of entry files of nextjs APIs, then pick up
them to let app router for bundling, instead of using the `next/<api
name>.js` CJS files. Those ESM entries still point to the `next/dist/..`
CJS files. In this way webpack and directly gets the exports from the
`next/dist/...` files and be aware of the module exports. No more CJS
module wrapping the ESM module, the default and named exports can
preserve correctly.
Fixes#54777
Closes NEXT-1774
Closes NEXT-1879
Closes NEXT-1923
### What?
When handling route interception in two different segments but handled
by the same interception route, the first interception will show the
correct component but attempting the same interception on another
segment will return elements from the first request, not the second.
### Why?
Prefetch cache entries are created from the browser URL. However, route
interception makes use of `nextUrl` to mask the underlying components
that are being fetched from the server to handle the request
Consider the following scenario:
```
app
foo
@modal
(...)post
[id]
bar
@modal
(...post)
[id]
post
[id]
```
If you trigger an interception on `/foo`, your URL is going to be masked
to `/post/1` and keyed as such in the prefetch cache. However, the cache
entry is actually associated with `app/foo/@modal/(...post)/[id]`. That
means when you trigger the same interception on `/bar`, it will return
the tree from `/foo`.
### How?
This PR will prefix the prefetch cache key with `state.nextUrl` when
necessary.
Fixes#49878Fixes#52748
Closes NEXT-1818
### What?
Catch-all routes are being matched to parallel routes which causes
issues like an interception route being handled by the wrong page
component, or a page component being associated with multiple pages
resulting in a "You cannot have two parallel pages that resolve to the
same path" build error.
### Why?
#58215 fixed a bug that caused catchall paths to not properly match when
used with parallel routes. In other words, a catchall slot wouldn't
render on a page that could match that catch all. Or a catchall page
wouldn't match a slot. At build time, a normalization step was
introduced to take application paths and attempt to perform this
matching behavior.
However in it's current form, this causes the errors mentioned above to
manifest. To better illustrate the problem, here are a few examples:
Given:
```
{
'/': [ '/page' ],
'/[...slug]': [ '/[...slug]/page' ],
'/items/[...ids]': [ '/items/[...ids]/page' ],
'/(.)items/[...ids]': [ '/@modal/(.)items/[...ids]/page' ]
}
```
The normalization logic would produce:
```
{
'/': [ '/page' ],
'/[...slug]': [ '/[...slug]/page' ],
'/items/[...ids]': [ '/items/[...ids]/page' ],
'/(.)items/[...ids]': [ '/@modal/(.)items/[...ids]/page', '/[...slug]/page' ]
}
```
The interception route will now be improperly handled by
`[...slug]/page` rather than the interception handler.
Another example, which rather than incorrectly handling a match, will
produce a build error:
Given:
```
{
'/': [ '/(group-b)/page' ],
'/[...catcher]': [ '/(group-a)/@parallel/[...catcher]/page' ]
}
```
The normalization logic would produce:
```
{
'/': [ '/(group-b)/page', '/(group-a)/@parallel/[...catcher]/page' ],
'/[...catcher]': [ '/(group-a)/@parallel/[...catcher]/page' ]
}
```
The parallel catch-all slot is now part of `/`. This means when building
the loader tree, two `children` parallel segments (aka page components)
will be found when hitting `/`, which is an error.
The error that was added here was originally intended to help catch
scenarios like:
`/app/(group-a)/page` and `/app/(group-b)/page`. However it also throws
for parallel slots, which isn't necessarily an error (especially since
the normalization logic will push potential matches).
### How?
There are two small fixes in this PR, the rest are an abundance of e2e
tests to help prevent regressions.
- When normalizing catch-all routes, we will not attempt to push any
page entrypoints for interception routes. These should already have all
the information they need in `appPaths`.
- Before throwing the error about duplicate page segments in
`next-app-loader`, we check to see if it's because we already matched a
page component but we also detected a parallel slot that would have
matched the page slot. In this case, we don't error, since the app can
recover from this.
- Loading a client reference manifest shouldn't throw a cryptic require
error. `loadClientReferenceManifest` is already potentially returning
undefined, so this case should already be handled gracefully
Separately, we'll need to follow-up on the Turbopack side to:
- Make sure the duplicate matching matches the Webpack implementation (I
believe Webpack is sorting, but Turbopack isn't)
- Implement #58215 in Turbopack. Once this is done, we should expect the
tests added in this PR to start failing.
Fixes#58272Fixes#58660Fixes#58312Fixes#59782Fixes#59784
Closes NEXT-1809
Adds a regression test and a fix for a bug that sometimes happens when a
prefetched route on the client becomes stale — the app would get stuck
in a loading state.
The problem was the condition I used to fallback to the non-PPR
implementation, inside navigateReducer. It was too narrow, causing
prefetched segments that contained dynamic holes to sometimes be treated
as if they were complete. The net effect was that the dynamic data would
never stream in, and the page would get stuck in a fallback state until
the stale prefetch was eventually purged from the cache, or the user
refreshed the page.
The reason the mistake happened was, as an incremental step, I decided
to fallback to the non-PPR implementation for any case where I hadn't
yet implemented the equivalent functionality. I think still think this
is a good strategy, despite the mistake, but I'm eager to get everything
migrated to the new model as soon as possible.
Closes NEXT-1920
We already have variables of swc loaders for different bundling layers,
the composed one should just be loaders instead of being called "swc
loader"
Closes NEXT-1917
If a user accidentally configures a non-valid `revalidate` value this
ensures we show a proper error message instead of silently tolerating
it.
Closes: NEXT-1896
Closes NEXT-1915
In #59725 I skipped this test in PPR prod mode, but not dev because CI
wasn't failing for dev. The idea was to investigate the failure
post-merge because it wasn't block-worthy.
But the test did fail in dev mode when CI ran on canary. So this updates
the guard to skip in dev, too.
Will follow up with a PR to fix the test itself.
Closes NEXT-1913