From 054ff7b117de6726ad468ded57f668f64f54db57 Mon Sep 17 00:00:00 2001 From: Liu Bowen Date: Tue, 6 Apr 2021 22:45:10 +0800 Subject: [PATCH 1/3] feat(router): router events type inference --- packages/next/client/router.ts | 12 ++++++++++-- packages/next/next-server/lib/mitt.ts | 11 +++++++---- packages/next/next-server/lib/router/router.ts | 11 +++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/next/client/router.ts b/packages/next/client/router.ts index 0506802441ad4f..72df4a9f784e0c 100644 --- a/packages/next/client/router.ts +++ b/packages/next/client/router.ts @@ -17,6 +17,14 @@ export { Router, NextRouter } export type SingletonRouter = SingletonRouterBase & NextRouter +export type RouterEvent = + | 'routeChangeStart' + | 'beforeHistoryChange' + | 'routeChangeComplete' + | 'routeChangeError' + | 'hashChangeStart' + | 'hashChangeComplete' + const singletonRouter: SingletonRouterBase = { router: null, // holds the actual router instance readyCallbacks: [], @@ -44,7 +52,7 @@ const urlPropertyFields = [ 'isPreview', 'isLocaleDomain', ] -const routerEvents = [ +const routerEvents: RouterEvent[] = [ 'routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', @@ -89,7 +97,7 @@ coreMethodFields.forEach((field: string) => { } }) -routerEvents.forEach((event: string) => { +routerEvents.forEach((event: RouterEvent) => { singletonRouter.ready(() => { Router.events.on(event, (...args) => { const eventField = `on${event.charAt(0).toUpperCase()}${event.substring( diff --git a/packages/next/next-server/lib/mitt.ts b/packages/next/next-server/lib/mitt.ts index e7c57c33b6e6cf..2452227f0a1fba 100644 --- a/packages/next/next-server/lib/mitt.ts +++ b/packages/next/next-server/lib/mitt.ts @@ -16,10 +16,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI type Handler = (...evts: any[]) => void -export type MittEmitter = { - on(type: string, handler: Handler): void - off(type: string, handler: Handler): void - emit(type: string, ...evts: any[]): void +export type MittEmitter< + Type extends string = string, + Func extends Handler = Handler +> = { + on(type: Type, handler: Func): void + off(type: Type, handler: Func): void + emit(type: Type, ...evts: any[]): void } export default function mitt(): MittEmitter { diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index e9502affb3ba2e..3cb105d134d878 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -13,6 +13,7 @@ import { isAssetError, markAssetError, } from '../../../client/route-loader' +import { RouterEvent } from '../../../client/router' import { DomainLocales } from '../../server/config' import { denormalizePagePath } from '../../server/denormalize-page-path' import { normalizeLocalePath } from '../i18n/normalize-locale-path' @@ -504,7 +505,10 @@ export default class Router implements BaseRouter { clc: ComponentLoadCancel pageLoader: any _bps: BeforePopStateCallback | undefined - events: MittEmitter + events: MittEmitter< + RouterEvent, + (url: string, routeProps: { shadow: boolean }) => void + > = mitt() _wrapApp: (App: AppComponent) => any isSsr: boolean isFallback: boolean @@ -520,7 +524,10 @@ export default class Router implements BaseRouter { private _idx: number = 0 - static events: MittEmitter = mitt() + static events: MittEmitter< + RouterEvent, + (url: string, routeProps: { shadow: boolean }) => void + > = mitt() constructor( pathname: string, From b37ee2ccafdcb5468f1e75ce1c732b678ca39a75 Mon Sep 17 00:00:00 2001 From: Liu Bowen Date: Wed, 7 Apr 2021 00:12:01 +0800 Subject: [PATCH 2/3] chore: rename shallow --- packages/next/next-server/lib/router/router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 3cb105d134d878..7153e2d560f6ff 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -507,7 +507,7 @@ export default class Router implements BaseRouter { _bps: BeforePopStateCallback | undefined events: MittEmitter< RouterEvent, - (url: string, routeProps: { shadow: boolean }) => void + (url: string, routeProps: { shallow: boolean }) => void > = mitt() _wrapApp: (App: AppComponent) => any isSsr: boolean @@ -526,7 +526,7 @@ export default class Router implements BaseRouter { static events: MittEmitter< RouterEvent, - (url: string, routeProps: { shadow: boolean }) => void + (url: string, routeProps: { shallow: boolean }) => void > = mitt() constructor( From ea4a19faffe175a2781b999a180c2cb58ad86974 Mon Sep 17 00:00:00 2001 From: Liu Bowen Date: Wed, 7 Apr 2021 01:17:32 +0800 Subject: [PATCH 3/3] feat: support routeChangeError --- packages/next/client/router.ts | 4 ++-- .../next/next-server/lib/router/router.ts | 23 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/next/client/router.ts b/packages/next/client/router.ts index 72df4a9f784e0c..f8681b98853128 100644 --- a/packages/next/client/router.ts +++ b/packages/next/client/router.ts @@ -97,9 +97,9 @@ coreMethodFields.forEach((field: string) => { } }) -routerEvents.forEach((event: RouterEvent) => { +routerEvents.forEach((event) => { singletonRouter.ready(() => { - Router.events.on(event, (...args) => { + Router.events.on(event as any, (...args: any[]) => { const eventField = `on${event.charAt(0).toUpperCase()}${event.substring( 1 )}` diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 7153e2d560f6ff..c0df8d8285f95c 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -425,6 +425,19 @@ type ComponentLoadCancel = (() => void) | null type HistoryMethod = 'replaceState' | 'pushState' +type RouterEventEmitter = MittEmitter< + Exclude, + (url: string, routeProps: { shallow: boolean }) => void +> & + MittEmitter< + 'routeChangeError', + ( + err: Error & { cancelled: boolean }, + url: string, + routeProps: { shallow: boolean } + ) => void + > + const manualScrollRestoration = process.env.__NEXT_SCROLL_RESTORATION && typeof window !== 'undefined' && @@ -505,10 +518,7 @@ export default class Router implements BaseRouter { clc: ComponentLoadCancel pageLoader: any _bps: BeforePopStateCallback | undefined - events: MittEmitter< - RouterEvent, - (url: string, routeProps: { shallow: boolean }) => void - > = mitt() + events: RouterEventEmitter = mitt() _wrapApp: (App: AppComponent) => any isSsr: boolean isFallback: boolean @@ -524,10 +534,7 @@ export default class Router implements BaseRouter { private _idx: number = 0 - static events: MittEmitter< - RouterEvent, - (url: string, routeProps: { shallow: boolean }) => void - > = mitt() + static events: RouterEventEmitter = mitt() constructor( pathname: string,