Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 10bdd06

Browse files
authored
Merge branch 'canary' into fix-examples-with-firebase-hosting
2 parents 5ab666d + 42e8dcf commit 10bdd06

File tree

25 files changed

+569
-191
lines changed

25 files changed

+569
-191
lines changed

lerna.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
"registry": "https://registry.npmjs.org/"
1818
}
1919
},
20-
"version": "9.5.3-canary.23"
20+
"version": "9.5.3-canary.24"
2121
}

packages/create-next-app/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "create-next-app",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"keywords": [
55
"react",
66
"next",

packages/eslint-plugin-next/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/eslint-plugin-next",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"description": "ESLint plugin for NextJS.",
55
"main": "lib/index.js",
66
"license": "MIT",

packages/next-bundle-analyzer/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/bundle-analyzer",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"main": "index.js",
55
"license": "MIT",
66
"repository": {

packages/next-codemod/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/codemod",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"license": "MIT",
55
"dependencies": {
66
"chalk": "4.1.0",

packages/next-mdx/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/mdx",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"main": "index.js",
55
"license": "MIT",
66
"repository": {

packages/next-plugin-google-analytics/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/plugin-google-analytics",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"repository": {
55
"url": "vercel/next.js",
66
"directory": "packages/next-plugin-google-analytics"

packages/next-plugin-sentry/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/plugin-sentry",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"repository": {
55
"url": "vercel/next.js",
66
"directory": "packages/next-plugin-sentry"

packages/next-plugin-storybook/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/plugin-storybook",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"repository": {
55
"url": "vercel/next.js",
66
"directory": "packages/next-plugin-storybook"

packages/next-polyfill-nomodule/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@next/polyfill-nomodule",
3-
"version": "9.5.3-canary.23",
3+
"version": "9.5.3-canary.24",
44
"description": "A polyfill for non-dead, nomodule browsers.",
55
"main": "dist/polyfill-nomodule.js",
66
"license": "MIT",

packages/next/client/index.tsx

+95-132
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import * as envConfig from '../next-server/lib/runtime-config'
1717
import { getURL, loadGetInitialProps, ST } from '../next-server/lib/utils'
1818
import type { NEXT_DATA } from '../next-server/lib/utils'
1919
import initHeadManager from './head-manager'
20-
import PageLoader, { createLink } from './page-loader'
20+
import PageLoader, { StyleSheetTuple } from './page-loader'
2121
import measureWebVitals from './performance-relayer'
2222
import { createRouter, makePublicRouterInstance } from './router'
2323

@@ -84,13 +84,25 @@ if (hasBasePath(asPath)) {
8484

8585
type RegisterFn = (input: [string, () => void]) => void
8686

87+
const looseToArray = <T extends {}>(input: any): T[] => [].slice.call(input)
88+
8789
const pageLoader = new PageLoader(
8890
buildId,
8991
prefix,
9092
page,
91-
[].slice
92-
.call(document.querySelectorAll('link[rel=stylesheet][data-n-p]'))
93-
.map((e: HTMLLinkElement) => e.getAttribute('href')!)
93+
looseToArray<CSSStyleSheet>(document.styleSheets)
94+
.filter(
95+
(el: CSSStyleSheet) =>
96+
el.ownerNode &&
97+
(el.ownerNode as Element).tagName === 'LINK' &&
98+
(el.ownerNode as Element).hasAttribute('data-n-p')
99+
)
100+
.map((sheet) => ({
101+
href: (sheet.ownerNode as Element).getAttribute('href')!,
102+
text: looseToArray<CSSRule>(sheet.cssRules)
103+
.map((r) => r.cssText)
104+
.join(''),
105+
}))
94106
)
95107
const register: RegisterFn = ([r, f]) => pageLoader.registerPage(r, f)
96108
if (window.__NEXT_P) {
@@ -109,7 +121,7 @@ let lastRenderReject: (() => void) | null
109121
let webpackHMR: any
110122
export let router: Router
111123
let CachedComponent: React.ComponentType
112-
let cachedStyleSheets: string[]
124+
let cachedStyleSheets: StyleSheetTuple[]
113125
let CachedApp: AppComponent, onPerfEntry: (metric: any) => void
114126

115127
class Container extends React.Component<{
@@ -574,8 +586,8 @@ function doRender({
574586
// lastAppProps has to be set before ReactDom.render to account for ReactDom throwing an error.
575587
lastAppProps = appProps
576588

589+
let canceled = false
577590
let resolvePromise: () => void
578-
let renderPromiseReject: () => void
579591
const renderPromise = new Promise((resolve, reject) => {
580592
if (lastRenderReject) {
581593
lastRenderReject()
@@ -584,7 +596,8 @@ function doRender({
584596
lastRenderReject = null
585597
resolve()
586598
}
587-
renderPromiseReject = lastRenderReject = () => {
599+
lastRenderReject = () => {
600+
canceled = true
588601
lastRenderReject = null
589602

590603
const error: any = new Error('Cancel rendering route')
@@ -593,12 +606,9 @@ function doRender({
593606
}
594607
})
595608

596-
// TODO: consider replacing this with real `<style>` tags that have
597-
// plain-text CSS content that's provided by RouteInfo. That'd remove the
598-
// need for the staging `<link>`s and the ability for CSS to be missing at
599-
// this phase, allowing us to remove the error handling flow that reloads the
600-
// page.
601-
function onStart(): Promise<void[]> {
609+
// This function has a return type to ensure it doesn't start returning a
610+
// Promise. It should remain synchronous.
611+
function onStart(): boolean {
602612
if (
603613
// We can skip this during hydration. Running it wont cause any harm, but
604614
// we may as well save the CPU cycles.
@@ -607,78 +617,27 @@ function doRender({
607617
// unless we're in production:
608618
process.env.NODE_ENV !== 'production'
609619
) {
610-
return Promise.resolve([])
620+
return false
611621
}
612622

613-
// Clean up previous render if canceling:
614-
;([].slice.call(
615-
document.querySelectorAll(
616-
'link[data-n-staging], noscript[data-n-staging]'
617-
)
618-
) as HTMLLinkElement[]).forEach((el) => {
619-
el.parentNode!.removeChild(el)
620-
})
621-
622-
const referenceNodes: HTMLLinkElement[] = [].slice.call(
623-
document.querySelectorAll('link[data-n-g], link[data-n-p]')
624-
) as HTMLLinkElement[]
625-
const referenceHrefs = new Set(
626-
referenceNodes.map((e) => e.getAttribute('href'))
623+
const currentStyleTags = looseToArray<HTMLStyleElement>(
624+
document.querySelectorAll('style[data-n-href]')
625+
)
626+
const currentHrefs = new Set(
627+
currentStyleTags.map((tag) => tag.getAttribute('data-n-href'))
627628
)
628-
let referenceNode: Element | undefined =
629-
referenceNodes[referenceNodes.length - 1]
630-
631-
const required: (Promise<any> | true)[] = styleSheets.map((href) => {
632-
let newNode: Element, promise: Promise<any> | true
633-
const existingLink = referenceHrefs.has(href)
634-
if (existingLink) {
635-
newNode = document.createElement('noscript')
636-
newNode.setAttribute('data-n-staging', href)
637-
promise = true
638-
} else {
639-
const [link, onload] = createLink(href, 'stylesheet')
640-
link.setAttribute('data-n-staging', '')
641-
// Media `none` does not work in Firefox, so `print` is more
642-
// cross-browser. Since this is so short lived we don't have to worry
643-
// about style thrashing in a print view (where no routing is going to be
644-
// happening anyway).
645-
link.setAttribute('media', 'print')
646-
newNode = link
647-
promise = onload
648-
}
649629

650-
if (referenceNode) {
651-
referenceNode.parentNode!.insertBefore(
652-
newNode,
653-
referenceNode.nextSibling
654-
)
655-
referenceNode = newNode
656-
} else {
657-
document.head.appendChild(newNode)
630+
styleSheets.forEach(({ href, text }) => {
631+
if (!currentHrefs.has(href)) {
632+
const styleTag = document.createElement('style')
633+
styleTag.setAttribute('data-n-href', href)
634+
styleTag.setAttribute('media', 'x')
635+
636+
document.head.appendChild(styleTag)
637+
styleTag.appendChild(document.createTextNode(text))
658638
}
659-
return promise
660-
})
661-
return Promise.all(required).catch(() => {
662-
// This is too late in the rendering lifecycle to use the existing
663-
// `PAGE_LOAD_ERROR` flow (via `handleRouteInfoError`).
664-
// To match that behavior, we request the page to reload with the current
665-
// asPath. This is already set at this phase since we "committed" to the
666-
// render.
667-
// This handles an edge case where a new deployment is rolled during
668-
// client-side transition and the CSS assets are missing.
669-
670-
// This prevents:
671-
// 1. An unstyled page from being rendered (old behavior)
672-
// 2. The `/_error` page being rendered (we want to reload for the new
673-
// deployment)
674-
window.location.href = router.asPath
675-
676-
// Instead of rethrowing the CSS loading error, we give a promise that
677-
// won't resolve. This pauses the rendering process until the page
678-
// reloads. Re-throwing the error could result in a flash of error page.
679-
// throw cssLoadingError
680-
return new Promise(() => {})
681639
})
640+
return true
682641
}
683642

684643
function onCommit() {
@@ -689,40 +648,58 @@ function doRender({
689648
// We can skip this during hydration. Running it wont cause any harm, but
690649
// we may as well save the CPU cycles:
691650
!isInitialRender &&
692-
// Ensure this render commit owns the currently staged stylesheets:
693-
renderPromiseReject === lastRenderReject
651+
// Ensure this render was not canceled
652+
!canceled
694653
) {
695-
// Remove or relocate old stylesheets:
696-
const relocatePlaceholders = [].slice.call(
697-
document.querySelectorAll('noscript[data-n-staging]')
698-
) as HTMLElement[]
699-
const relocateHrefs = relocatePlaceholders.map((e) =>
700-
e.getAttribute('data-n-staging')
654+
const desiredHrefs = new Set(styleSheets.map((s) => s.href))
655+
const currentStyleTags = looseToArray<HTMLStyleElement>(
656+
document.querySelectorAll('style[data-n-href]')
701657
)
702-
;([].slice.call(
703-
document.querySelectorAll('link[data-n-p]')
704-
) as HTMLLinkElement[]).forEach((el) => {
705-
const currentHref = el.getAttribute('href')
706-
const relocateIndex = relocateHrefs.indexOf(currentHref)
707-
if (relocateIndex !== -1) {
708-
const placeholderElement = relocatePlaceholders[relocateIndex]
709-
placeholderElement.parentNode?.replaceChild(el, placeholderElement)
658+
const currentHrefs = currentStyleTags.map(
659+
(tag) => tag.getAttribute('data-n-href')!
660+
)
661+
662+
// Toggle `<style>` tags on or off depending on if they're needed:
663+
for (let idx = 0; idx < currentHrefs.length; ++idx) {
664+
if (desiredHrefs.has(currentHrefs[idx])) {
665+
currentStyleTags[idx].removeAttribute('media')
710666
} else {
711-
el.parentNode!.removeChild(el)
667+
currentStyleTags[idx].setAttribute('media', 'x')
712668
}
713-
})
669+
}
714670

715-
// Activate new stylesheets:
716-
;[].slice
717-
.call(document.querySelectorAll('link[data-n-staging]'))
718-
.forEach((el: HTMLLinkElement) => {
719-
el.removeAttribute('data-n-staging')
720-
el.removeAttribute('media')
721-
el.setAttribute('data-n-p', '')
671+
// Reorder styles into intended order:
672+
let referenceNode = document.querySelector('noscript[data-n-css]')
673+
if (
674+
// This should be an invariant:
675+
referenceNode
676+
) {
677+
styleSheets.forEach(({ href }) => {
678+
const targetTag = document.querySelector(
679+
`style[data-n-href="${href}"]`
680+
)
681+
if (
682+
// This should be an invariant:
683+
targetTag
684+
) {
685+
referenceNode!.parentNode!.insertBefore(
686+
targetTag,
687+
referenceNode!.nextSibling
688+
)
689+
referenceNode = targetTag
690+
}
722691
})
692+
}
693+
694+
// Finally, clean up server rendered stylesheets:
695+
looseToArray<HTMLLinkElement>(
696+
document.querySelectorAll('link[data-n-p]')
697+
).forEach((el) => {
698+
el.parentNode!.removeChild(el)
699+
})
723700

724-
// Force browser to recompute layout, which prevents a flash of unstyled
725-
// content:
701+
// Force browser to recompute layout, which should prevent a flash of
702+
// unstyled content:
726703
getComputedStyle(document.body, 'height')
727704
}
728705

@@ -737,33 +714,19 @@ function doRender({
737714
</Root>
738715
)
739716

717+
onStart()
718+
740719
// We catch runtime errors using componentDidCatch which will trigger renderError
741-
return Promise.race([
742-
// Download required CSS assets first:
743-
onStart()
744-
.then(() => {
745-
// Ensure a new render has not been started:
746-
if (renderPromiseReject === lastRenderReject) {
747-
// Queue rendering:
748-
renderReactElement(
749-
process.env.__NEXT_STRICT_MODE ? (
750-
<React.StrictMode>{elem}</React.StrictMode>
751-
) : (
752-
elem
753-
),
754-
appElement!
755-
)
756-
}
757-
})
758-
.then(
759-
() =>
760-
// Wait for rendering to complete:
761-
renderPromise
762-
),
763-
764-
// Bail early on route cancelation (rejection):
765-
renderPromise,
766-
])
720+
renderReactElement(
721+
process.env.__NEXT_STRICT_MODE ? (
722+
<React.StrictMode>{elem}</React.StrictMode>
723+
) : (
724+
elem
725+
),
726+
appElement!
727+
)
728+
729+
return renderPromise
767730
}
768731

769732
function Root({

0 commit comments

Comments
 (0)