90f95399dd
### What? When relying on a `default` route as a fallback, greedier catch-all segments in the application hierarchy would take precedence, causing unexpected errors/matching behavior. ### Why? When performing parallel route catch-all normalization, we push potential catch-all matches to paths without considering that a path might instead be matched by a `default` page. Because of this, the catch-all take precedence and the app will not try and load the default. For example, given this structure: ``` { "/": ["/page"], "/[[...catchAll]]": ["/[[...catchAll]]/page"], "/nested/[foo]/[bar]": ["/nested/[foo]/[bar]/@slot/page"], "/nested/[foo]/[bar]/[baz]": ["/nested/[foo]/[bar]/@slot/[baz]/page"], } ``` (Where there's a `/nested/[foo]/[bar]/default.tsx`) The route normalization logic would produce: ``` { "/": ["/page"], "/[[...catchAll]]": ["/[[...catchAll]]/page"], "/nested/[foo]/[bar]": [ "/nested/[foo]/[bar]/@slot/page", "/[[...catchAll]]/page", ], "/nested/[foo]/[bar]/[baz]": [ "/nested/[foo]/[bar]/@slot/[baz]/page", "/[[...catchAll]]/page", ], } ``` This means that when building the `LoaderTree`, it won't ever try to find the default for that segment. **This solution operates under the assumption that if you defined a `default` at a particular layout segment, you intend for that to render in place of a greedier catch-all.** (Let me know if this is an incorrect assumption) ### How? We can't safely normalize catch-all parallel routes without having context about where the `default` segments are, so this updates `appPaths` to be inclusive of default segments and then filters them when doing anything relating to build/export to maintain existing behavior. We use this information to check if an existing default exists at the same segment level that we'd push the catch-all to. If one exists, we don't push the catch-all. Otherwise we proceed as normal. Closes NEXT-1987 |
||
---|---|---|
.. | ||
app | ||
next.config.js | ||
parallel-routes-catchall-default.test.ts |