Fix not found css not being preloaded while navigation (#53906)

### Problem

One style of `not-found` has `precendence` property with "undefined" value, which can't be handled by React Float, then during navigation the style could not load properly, lead to the style missing in issue #53210.

### Solution

Always enable `precendence` for all links, so all the css styles of page and convention components can be hoist by react properly. Float will decide which one should be handled. Previously this change only applies to template, actually we can apply it to all components so that they can all be handled properly especially during client navigation.

Related react change: https://github.com/facebook/react/pull/27265
Fixes #53210
This commit is contained in:
Jiachi Liu 2023-08-23 15:07:30 +02:00 committed by GitHub
parent 06be3c6cf5
commit 9834ab7e15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 147 additions and 13 deletions

View file

@ -82,6 +82,7 @@
"@next/swc": "workspace:*",
"@next/third-parties": "workspace:*",
"@opentelemetry/api": "1.4.1",
"@picocss/pico": "1.5.10",
"@svgr/webpack": "5.5.0",
"@swc/cli": "0.1.55",
"@swc/core": "1.3.55",

View file

@ -401,12 +401,10 @@ export async function renderToHTMLOrFlight(
const createComponentAndStyles = async ({
filePath,
getComponent,
shouldPreload,
injectedCSS,
}: {
filePath: string
getComponent: () => any
shouldPreload?: boolean
injectedCSS: Set<string>
}): Promise<any> => {
const cssHrefs = getCssInlinedLinkTags(
@ -433,11 +431,8 @@ export async function renderToHTMLOrFlight(
// During HMR, it's critical to use different `precedence` values
// for different stylesheets, so their order will be kept.
// https://github.com/facebook/react/pull/25060
const precedence = shouldPreload
? process.env.NODE_ENV === 'development'
? 'next_' + href
: 'next'
: undefined
const precedence =
process.env.NODE_ENV === 'development' ? 'next_' + href : 'next'
return (
<link
@ -614,7 +609,6 @@ export async function renderToHTMLOrFlight(
? await createComponentAndStyles({
filePath: template[1],
getComponent: template[0],
shouldPreload: true,
injectedCSS: injectedCSSWithCurrentLayout,
})
: [React.Fragment]

View file

@ -92,6 +92,9 @@ importers:
'@opentelemetry/api':
specifier: 1.4.1
version: 1.4.1
'@picocss/pico':
specifier: 1.5.10
version: 1.5.10
'@svgr/webpack':
specifier: 5.5.0
version: 5.5.0
@ -7292,6 +7295,10 @@ packages:
engines: {node: '>=14'}
dev: true
/@picocss/pico@1.5.10:
resolution: {integrity: sha512-+LafMsrwPxXQMk6sI///TmSInCwwZmq+K7SikyL3N/4GhhwzyPC+TQLUEqmrLyjluR+uIpFFcqjty30Rtr6GxQ==}
dev: true
/@pkgr/utils@2.3.1:
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}

View file

@ -175,11 +175,11 @@ createNextDescribe(
describe('special entries', () => {
it('should include css imported in loading.js', async () => {
const html = await next.render('/loading-bug/hi')
// The link tag should be included together with loading
expect(html).toMatch(
/<link rel="stylesheet" href="(.+)\.css(\?v=\d+)?"\/><h2>Loading...<\/h2>/
)
const $ = await next.render$('/loading-bug/hi')
// The link tag should be hoist into head with precedence properties
expect($('head link[data-precedence]').length).toBe(2)
expect($('body h2').text()).toBe('Loading...')
})
it('should include css imported in client template.js', async () => {

View file

@ -0,0 +1,7 @@
export default function Layout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}

View file

@ -0,0 +1,23 @@
'use client'
import { Button } from '../components/button/button'
import { useRouter } from 'next/navigation'
function NotFound() {
const router = useRouter()
return (
<div>
<h1>404 - Page Not Found</h1>
<Button
id="go-to-index"
onClick={() => {
router.push('/')
}}
>
Home
</Button>
</div>
)
}
export default NotFound

View file

@ -0,0 +1,20 @@
'use client'
import { useRouter } from 'next/navigation'
import { Button } from '../components/button/button'
export default function Page() {
const router = useRouter()
return (
<>
<Button
id="go-to-404"
onClick={() => {
router.push('/404')
}}
>
Not Found
</Button>
</>
)
}

View file

@ -0,0 +1,12 @@
'use client'
import styles from './button.module.css'
import React from 'react'
export const Button = ({ children, ...props }) => {
return (
<button {...props} className={styles.button}>
{children}
</button>
)
}

View file

@ -0,0 +1,7 @@
.button {
border: 1px solid #ccc;
border-radius: 4px;
background: rgb(0, 128, 0);
color: #fff;
padding: 8px 16px;
}

View file

@ -0,0 +1,20 @@
'use client'
import { Button } from './button/button'
import { useRouter } from 'next/navigation'
export default function Navigate404Section() {
const router = useRouter()
return (
<p>
<Button
id="go-to-navigate-404"
onClick={() => {
router.push('/navigate-404')
}}
>
Go to /navigate-404
</Button>
</p>
)
}

View file

@ -0,0 +1,43 @@
import { createNextDescribe } from 'e2e-utils'
import { check } from 'next-test-utils'
createNextDescribe(
'app dir css',
{
files: __dirname,
skipDeployment: true,
dependencies: {
sass: 'latest',
},
},
({ next }) => {
it('should load css while navigation between not-found and page', async () => {
const browser = await next.browser('/')
await check(
async () =>
await browser.eval(
`window.getComputedStyle(document.querySelector('#go-to-404')).backgroundColor`
),
'rgb(0, 128, 0)'
)
await browser.elementByCss('#go-to-404').click()
await browser.waitForElementByCss('#go-to-index')
await check(
async () =>
await browser.eval(
`window.getComputedStyle(document.querySelector('#go-to-index')).backgroundColor`
),
'rgb(0, 128, 0)'
)
await browser.elementByCss('#go-to-index').click()
await browser.waitForElementByCss('#go-to-404')
await check(
async () =>
await browser.eval(
`window.getComputedStyle(document.querySelector('#go-to-404')).backgroundColor`
),
'rgb(0, 128, 0)'
)
})
}
)