From 16e4f9e79ef804221b7a761ced2971842fff98a5 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Wed, 12 Aug 2020 23:54:48 -0400 Subject: [PATCH 1/3] Strongly type Head Manager (#16144) --- .../{head-manager.js => head-manager.ts} | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) rename packages/next/client/{head-manager.js => head-manager.ts} (69%) diff --git a/packages/next/client/head-manager.js b/packages/next/client/head-manager.ts similarity index 69% rename from packages/next/client/head-manager.js rename to packages/next/client/head-manager.ts index eccf2fc1a4aa9..424613f75db21 100644 --- a/packages/next/client/head-manager.js +++ b/packages/next/client/head-manager.ts @@ -1,11 +1,11 @@ -const DOMAttributeNames = { +const DOMAttributeNames: Record = { 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 @@ -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( @@ -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 | 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 = {} head.forEach((h) => { const components = tags[h.type] || [] From 94a85cff12cb37ecbdc88ca0360e467945d1e393 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 13 Aug 2020 00:01:15 -0400 Subject: [PATCH 2/3] Improve page loader types (#16145) --- packages/next/client/page-loader.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/next/client/page-loader.ts b/packages/next/client/page-loader.ts index 880bb2722f0e4..e48c6585b6e28 100644 --- a/packages/next/client/page-loader.ts +++ b/packages/next/client/page-loader.ts @@ -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 @@ -225,26 +226,29 @@ export default class PageLoader { ) } - loadPage(route: string) { + loadPage(route: string): Promise { route = normalizeRoute(route) - return new Promise((resolve, reject) => { + return new Promise((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) } } From d81ace268a43e83ddae98fa339dc825ea69a5b43 Mon Sep 17 00:00:00 2001 From: madiknox <59509185+madiknox@users.noreply.github.com> Date: Thu, 13 Aug 2020 00:21:27 -0400 Subject: [PATCH 3/3] removed renderToHTML definition from with-flow example (#16137) This is my very first PR, I'm hoping to contribute more. Should I also remove `renderErrorToHTML` and `renderError`? #14737 --- examples/with-flow/flow-typed/next.js.flow | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/with-flow/flow-typed/next.js.flow b/examples/with-flow/flow-typed/next.js.flow index 102b81a5d5010..e5b2756d88722 100644 --- a/examples/with-flow/flow-typed/next.js.flow +++ b/examples/with-flow/flow-typed/next.js.flow @@ -5,9 +5,6 @@ declare module "next" { prepare(): Promise; 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 }