Skip to content

Commit

Permalink
Font optimization bugfix vercel#23896
Browse files Browse the repository at this point in the history
  • Loading branch information
janicklas-ralph committed Apr 16, 2021
1 parent 0acfd84 commit 2c320c4
Showing 1 changed file with 27 additions and 43 deletions.
70 changes: 27 additions & 43 deletions packages/next/next-server/lib/post-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,9 @@ type postProcessOptions = {
type renderOptions = {
getFontDefinition?: (url: string) => string
}

type postProcessData = {
preloads: {
images: Array<string>
}
}

interface PostProcessMiddleware {
inspect: (
originalDom: HTMLElement,
data: postProcessData,
options: renderOptions
) => void
mutate: (
markup: string,
data: postProcessData,
options: renderOptions
) => Promise<string>
inspect: (originalDom: HTMLElement, options: renderOptions) => any
mutate: (markup: string, data: any, options: renderOptions) => Promise<string>
}

type middlewareSignature = {
Expand Down Expand Up @@ -58,18 +43,14 @@ async function processHTML(
if (!middlewareRegistry[0]) {
return html
}
const postProcessData: postProcessData = {
preloads: {
images: [],
},
}

const root: HTMLElement = parse(html)
let document = html
// Calls the middleware, with some instrumentation and logging
async function callMiddleWare(middleware: PostProcessMiddleware) {
// let timer = Date.now()
middleware.inspect(root, postProcessData, data)
document = await middleware.mutate(document, postProcessData, data)
const inspectData = middleware.inspect(root, data)
document = await middleware.mutate(document, inspectData, data)
// timer = Date.now() - timer
// if (timer > MIDDLEWARE_TIME_BUDGET) {
// TODO: Identify a correct upper limit for the postprocess step
Expand All @@ -89,15 +70,11 @@ async function processHTML(
}

class FontOptimizerMiddleware implements PostProcessMiddleware {
fontDefinitions: (string | undefined)[][] = []
inspect(
originalDom: HTMLElement,
_data: postProcessData,
options: renderOptions
) {
inspect(originalDom: HTMLElement, options: renderOptions) {
if (!options.getFontDefinition) {
return
}
const fontDefinitions: (string | undefined)[][] = []
// collecting all the requested font definitions
originalDom
.querySelectorAll('link')
Expand All @@ -115,30 +92,35 @@ class FontOptimizerMiddleware implements PostProcessMiddleware {
const nonce = element.getAttribute('nonce')

if (url) {
this.fontDefinitions.push([url, nonce])
fontDefinitions.push([url, nonce])
}
})

return fontDefinitions
}
mutate = async (
markup: string,
_data: postProcessData,
fontDefinitions: string[][],
options: renderOptions
) => {
let result = markup
if (!options.getFontDefinition) {
return markup
}
for (const key in this.fontDefinitions) {
const [url, nonce] = this.fontDefinitions[key]

fontDefinitions.forEach((fontDef) => {
const [url, nonce] = fontDef
const fallBackLinkTag = `<link rel="stylesheet" href="${url}"/>`
if (
result.indexOf(`<style data-href="${url}">`) > -1 ||
result.indexOf(fallBackLinkTag) > -1
) {
// The font is already optimized and probably the response is cached
continue
return
}
const fontContent = options.getFontDefinition(url as string)
const fontContent = options.getFontDefinition
? options.getFontDefinition(url as string)
: null
if (!fontContent) {
/**
* In case of unreachable font definitions, fallback to default link tag.
Expand All @@ -151,13 +133,15 @@ class FontOptimizerMiddleware implements PostProcessMiddleware {
`<style data-href="${url}"${nonceStr}>${fontContent}</style></head>`
)
}
}
})

return result
}
}

class ImageOptimizerMiddleware implements PostProcessMiddleware {
inspect(originalDom: HTMLElement, _data: postProcessData) {
inspect(originalDom: HTMLElement) {
const imgPreloads = []
const imgElements = originalDom.querySelectorAll('img')
let eligibleImages: Array<HTMLElement> = []
for (let i = 0; i < imgElements.length; i++) {
Expand All @@ -169,18 +153,18 @@ class ImageOptimizerMiddleware implements PostProcessMiddleware {
}
}

_data.preloads.images = []

for (const imgEl of eligibleImages) {
const src = imgEl.getAttribute('src')
if (src) {
_data.preloads.images.push(src)
imgPreloads.push(src)
}
}

return imgPreloads
}
mutate = async (markup: string, _data: postProcessData) => {
mutate = async (markup: string, imgPreloads: string[]) => {
let result = markup
let imagePreloadTags = _data.preloads.images
let imagePreloadTags = imgPreloads
.filter((imgHref) => !preloadTagAlreadyExists(markup, imgHref))
.reduce(
(acc, imgHref) =>
Expand Down

0 comments on commit 2c320c4

Please sign in to comment.