Skip to content

Commit

Permalink
Merge branch 'canary' into ssr-caching
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Aug 13, 2020
2 parents 7a87250 + d81ace2 commit c5c545e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 32 deletions.
3 changes: 0 additions & 3 deletions examples/with-flow/flow-typed/next.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ declare module "next" {
prepare(): Promise<void>;
getRequestHandler(): any;
render(req: any, res: any, pathname: string, query: any): any;
renderToHTML(req: any, res: any, pathname: string, query: string): string;
renderError(err: Error, req: any, res: any, pathname: any, query: any): any;
renderErrorToHTML(err: Error, req: any, res: any, pathname: string, query: any): string;
};
declare module.exports: (...opts: any) => NextApp
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const DOMAttributeNames = {
const DOMAttributeNames: Record<string, string> = {
acceptCharset: 'accept-charset',
className: 'class',
htmlFor: 'for',
httpEquiv: 'http-equiv',
}

function reactElementToDOM({ type, props }) {
function reactElementToDOM({ type, props }: JSX.Element): HTMLElement {
const el = document.createElement(type)
for (const p in props) {
if (!props.hasOwnProperty(p)) continue
Expand All @@ -27,9 +27,11 @@ function reactElementToDOM({ type, props }) {
return el
}

function updateElements(type, components) {
function updateElements(type: string, components: JSX.Element[]) {
const headEl = document.getElementsByTagName('head')[0]
const headCountEl = headEl.querySelector('meta[name=next-head-count]')
const headCountEl: HTMLMetaElement = headEl.querySelector(
'meta[name=next-head-count]'
) as HTMLMetaElement
if (process.env.NODE_ENV !== 'production') {
if (!headCountEl) {
console.error(
Expand All @@ -40,44 +42,46 @@ function updateElements(type, components) {
}

const headCount = Number(headCountEl.content)
const oldTags = []
const oldTags: Element[] = []

for (
let i = 0, j = headCountEl.previousElementSibling;
i < headCount;
i++, j = j.previousElementSibling
i++, j = j!.previousElementSibling
) {
if (j.tagName.toLowerCase() === type) {
oldTags.push(j)
if (j!.tagName.toLowerCase() === type) {
oldTags.push(j!)
}
}
const newTags = components.map(reactElementToDOM).filter((newTag) => {
for (let k = 0, len = oldTags.length; k < len; k++) {
const oldTag = oldTags[k]
if (oldTag.isEqualNode(newTag)) {
oldTags.splice(k, 1)
return false
const newTags = (components.map(reactElementToDOM) as HTMLElement[]).filter(
(newTag) => {
for (let k = 0, len = oldTags.length; k < len; k++) {
const oldTag = oldTags[k]
if (oldTag.isEqualNode(newTag)) {
oldTags.splice(k, 1)
return false
}
}
return true
}
return true
})
)

oldTags.forEach((t) => t.parentNode.removeChild(t))
oldTags.forEach((t) => t.parentNode!.removeChild(t))
newTags.forEach((t) => headEl.insertBefore(t, headCountEl))
headCountEl.content = (headCount - oldTags.length + newTags.length).toString()
}

export default function initHeadManager() {
let updatePromise = null
let updatePromise: Promise<void> | null = null

return {
mountedInstances: new Set(),
updateHead: (head) => {
updateHead: (head: JSX.Element[]) => {
const promise = (updatePromise = Promise.resolve().then(() => {
if (promise !== updatePromise) return

updatePromise = null
const tags = {}
const tags: Record<string, JSX.Element[]> = {}

head.forEach((h) => {
const components = tags[h.type] || []
Expand Down
22 changes: 13 additions & 9 deletions packages/next/client/page-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ function appendLink(
})
}

type PageCacheEntry = { error?: any; page?: any; mod?: any }
export type GoodPageCache = { page: any; mod: any }
export type PageCacheEntry = { error: any } | GoodPageCache

export default class PageLoader {
private buildId: string
Expand Down Expand Up @@ -225,26 +226,29 @@ export default class PageLoader {
)
}

loadPage(route: string) {
loadPage(route: string): Promise<GoodPageCache> {
route = normalizeRoute(route)

return new Promise((resolve, reject) => {
return new Promise<GoodPageCache>((resolve, reject) => {
// If there's a cached version of the page, let's use it.
const cachedPage = this.pageCache[route]
if (cachedPage) {
const { error, page, mod } = cachedPage
error ? reject(error) : resolve({ page, mod })
if ('error' in cachedPage) {
reject(cachedPage.error)
} else {
resolve(cachedPage)
}
return
}

const fire = ({ error, page, mod }: PageCacheEntry) => {
const fire = (pageToCache: PageCacheEntry) => {
this.pageRegisterEvents.off(route, fire)
delete this.loadingRoutes[route]

if (error) {
reject(error)
if ('error' in pageToCache) {
reject(pageToCache.error)
} else {
resolve({ page, mod })
resolve(pageToCache)
}
}

Expand Down

0 comments on commit c5c545e

Please sign in to comment.