Skip to content

Commit 328abb7

Browse files
authored
Do not rely on cssText (#16611)
1 parent 42e8dcf commit 328abb7

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

packages/next/client/index.tsx

Lines changed: 2 additions & 21 deletions
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, { StyleSheetTuple } from './page-loader'
20+
import PageLoader, { looseToArray, StyleSheetTuple } from './page-loader'
2121
import measureWebVitals from './performance-relayer'
2222
import { createRouter, makePublicRouterInstance } from './router'
2323

@@ -84,26 +84,7 @@ if (hasBasePath(asPath)) {
8484

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

87-
const looseToArray = <T extends {}>(input: any): T[] => [].slice.call(input)
88-
89-
const pageLoader = new PageLoader(
90-
buildId,
91-
prefix,
92-
page,
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-
}))
106-
)
87+
const pageLoader = new PageLoader(buildId, prefix, page)
10788
const register: RegisterFn = ([r, f]) => pageLoader.registerPage(r, f)
10889
if (window.__NEXT_P) {
10990
// Defer page registration for another tick. This will increase the overall

packages/next/client/page-loader.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,25 @@ import { searchParamsToUrlQuery } from '../next-server/lib/router/utils/querystr
1212
import { getRouteMatcher } from '../next-server/lib/router/utils/route-matcher'
1313
import { getRouteRegex } from '../next-server/lib/router/utils/route-regex'
1414

15+
export const looseToArray = <T extends {}>(input: any): T[] =>
16+
[].slice.call(input)
17+
18+
function getInitialStylesheets(): StyleSheetTuple[] {
19+
return looseToArray<CSSStyleSheet>(document.styleSheets)
20+
.filter(
21+
(el: CSSStyleSheet) =>
22+
el.ownerNode &&
23+
(el.ownerNode as Element).tagName === 'LINK' &&
24+
(el.ownerNode as Element).hasAttribute('data-n-p')
25+
)
26+
.map((sheet) => ({
27+
href: (sheet.ownerNode as Element).getAttribute('href')!,
28+
text: looseToArray<CSSRule>(sheet.cssRules)
29+
.map((r) => r.cssText)
30+
.join(''),
31+
}))
32+
}
33+
1534
function hasRel(rel: string, link?: HTMLLinkElement) {
1635
try {
1736
link = document.createElement('link')
@@ -99,7 +118,6 @@ export type PageCacheEntry = { error: any } | GoodPageCache
99118

100119
export default class PageLoader {
101120
private initialPage: string
102-
private initialStyleSheets: StyleSheetTuple[]
103121
private buildId: string
104122
private assetPrefix: string
105123
private pageCache: Record<string, PageCacheEntry>
@@ -109,14 +127,8 @@ export default class PageLoader {
109127
private promisedSsgManifest?: Promise<ClientSsgManifest>
110128
private promisedDevPagesManifest?: Promise<any>
111129

112-
constructor(
113-
buildId: string,
114-
assetPrefix: string,
115-
initialPage: string,
116-
initialStyleSheets: StyleSheetTuple[]
117-
) {
130+
constructor(buildId: string, assetPrefix: string, initialPage: string) {
118131
this.initialPage = initialPage
119-
this.initialStyleSheets = initialStyleSheets
120132

121133
this.buildId = buildId
122134
this.assetPrefix = assetPrefix
@@ -422,23 +434,34 @@ export default class PageLoader {
422434
})
423435
}
424436

437+
const isInitialLoad = route === this.initialPage
425438
const promisedDeps: Promise<StyleSheetTuple[]> =
426439
// Shared styles will already be on the page:
427440
route === '/_app' ||
428441
// We use `style-loader` in development:
429442
process.env.NODE_ENV !== 'production'
430443
? Promise.resolve([])
431-
: route === this.initialPage
432-
? Promise.resolve(this.initialStyleSheets)
433444
: // Tests that this does not block hydration:
434445
// test/integration/css-fixtures/hydrate-without-deps/
435-
this.getDependencies(route)
436-
.then((deps) => deps.filter((d) => d.endsWith('.css')))
437-
.then((cssFiles) =>
438-
// These files should've already been fetched by now, so this
439-
// should resolve pretty much instantly.
440-
Promise.all(cssFiles.map((d) => fetchStyleSheet(d)))
446+
(isInitialLoad
447+
? Promise.resolve(
448+
looseToArray<HTMLLinkElement>(
449+
document.querySelectorAll('link[data-n-p]')
450+
).map((e) => e.getAttribute('href')!)
451+
)
452+
: this.getDependencies(route).then((deps) =>
453+
deps.filter((d) => d.endsWith('.css'))
454+
)
455+
).then((cssFiles) =>
456+
// These files should've already been fetched by now, so this
457+
// should resolve instantly.
458+
Promise.all(cssFiles.map((d) => fetchStyleSheet(d))).catch(
459+
(err) => {
460+
if (isInitialLoad) return getInitialStylesheets()
461+
throw err
462+
}
441463
)
464+
)
442465
promisedDeps.then(
443466
(deps) => register(deps),
444467
(error) => {

0 commit comments

Comments
 (0)