Skip to content

Commit

Permalink
fix issues loading CSS in default slots (#61428)
Browse files Browse the repository at this point in the history
### What
When using a default slot that re-exports another page, the CSS entries
(and presumably other client reference modules, like JS entries) that
correspond with the re-exported page won't be loaded, resulting in CSS
styles not being applied.

### Why
`next-app-loader` constructs the path to the default segment but special
cases the `children` slot (which is used as the page), to mark the
segment as an empty string. This is so that the parallel default file
can be loaded. However the way that `defaultPath` is constructed, it
assumes that `actualSegment` won't be an empty string, and constructs an
invalid path like so:

`app/example//default.tsx`

When we go to look up the JS/CSS entries from the client reference
manifest, the key will be incorrect and so it won't find the files for
it, resulting in this bug.

### How
This moves the `/` delimiting to be part of the creation of the
`actualSegment` variable so that we only append it when we know we
aren't setting it to be an empty string.

Fixes #52245
Fixes #49871
Closes NEXT-2309
Closes NEXT-2310
  • Loading branch information
ztanner authored Jan 31, 2024
1 parent 70900ce commit 8714166
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 2 deletions.
6 changes: 4 additions & 2 deletions packages/next/src/build/webpack/loaders/next-app-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,11 @@ async function createTreeCodeFromPath(
for (const adjacentParallelSegment of adjacentParallelSegments) {
if (!props[normalizeParallelKey(adjacentParallelSegment)]) {
const actualSegment =
adjacentParallelSegment === 'children' ? '' : adjacentParallelSegment
adjacentParallelSegment === 'children'
? ''
: `/${adjacentParallelSegment}`
let defaultPath = await resolver(
`${appDirPrefix}${segmentPath}/${actualSegment}/default`
`${appDirPrefix}${segmentPath}${actualSegment}/default`
)

if (!defaultPath) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Default() {
return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <div>This is more</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './page'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.red {
color: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Link from 'next/link'
import styles from './page.module.css'

export default function Example() {
return (
<div>
<h1>Example</h1>
<p className={styles.red} id="red-text">
This is red
</p>
<p>
<Link href="/default-css/more">Show more</Link>
</p>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,34 @@ createNextDescribe(
)
})

it('should load CSS for a default page that exports another page', async () => {
const browser = await next.browser('/default-css')

expect(
await browser.eval(
`window.getComputedStyle(document.getElementById("red-text")).color`
)
).toBe('rgb(255, 0, 0)')

// the more page will now be using the page's `default.tsx` file, which re-exports the root page.
await browser.elementByCss('[href="/default-css/more"]').click()

expect(
await browser.eval(
`window.getComputedStyle(document.getElementById("red-text")).color`
)
).toBe('rgb(255, 0, 0)')

// ensure that everything still works on a fresh load
await browser.refresh()

expect(
await browser.eval(
`window.getComputedStyle(document.getElementById("red-text")).color`
)
).toBe('rgb(255, 0, 0)')
})

if (isNextDev) {
it('should support parallel routes with no page component', async () => {
const browser = await next.browser('/parallel-no-page/foo')
Expand Down

0 comments on commit 8714166

Please sign in to comment.