Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add string literal type for router events #15497

Closed
wants to merge 117 commits into from
Closed
Show file tree
Hide file tree
Changes from 114 commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
8ed2aa3
Add string literal type for router events
LauraBeatris Jul 26, 2020
ff4171c
Accept string types for events
LauraBeatris Jul 26, 2020
c93b9b1
Move router event type to router
LauraBeatris Jul 26, 2020
0476b70
Add generic type for mitt
timneutkens Jul 29, 2020
3483e1a
Add generic for mitt event handlers
LauraBeatris Jul 30, 2020
1d76bdf
Pass type for router event handler
LauraBeatris Jul 30, 2020
f4e0aae
Add EventMap to mitt
LauraBeatris Jul 30, 2020
989b53c
Add static tweet link (#15493)
timneutkens Jul 26, 2020
a43cade
Upgrade cssnano-simple dependency (#15488)
Timer Jul 27, 2020
46a8b4a
v9.4.5-canary.44
Timer Jul 27, 2020
255bf5e
Fix peer dependency (#15511)
Timer Jul 27, 2020
ef2fc0d
v9.4.5-canary.45
Timer Jul 27, 2020
d0ddc9f
Update custom webpack config docs to mention existing features (#15517)
timneutkens Jul 27, 2020
ce193a9
v9.5.0
timneutkens Jul 27, 2020
7bc1d5e
upgrade @ampproject/toolbox-optimizer to 2.5.14 (#15463)
sebastianbenz Jul 27, 2020
4a51dfd
Update `gssp-export` Error (#15529)
Timer Jul 27, 2020
eb5d74e
fix typo in custom-webpack-config docs (#15533)
cvan Jul 27, 2020
3f647ae
Combine sendPayload and sendHTML (#15475)
devknoll Jul 27, 2020
e804d5e
[update] 'yo' to 'you' (#15545)
ywppp Jul 28, 2020
24eaffd
[Docs] Update links that should point to Vercel repos (#15547)
lfades Jul 28, 2020
edffabb
Update Apollo example for 9.5 (#15546)
0xHexE Jul 28, 2020
cbce43d
Update revalidate examples for 9.5 (#15551)
Timer Jul 28, 2020
76bef4e
[Docs] Performance time is in milliseconds (#15544)
lfades Jul 28, 2020
0982e62
De-experimentalize redirects for rosetta example (#15554)
Timer Jul 28, 2020
53d67c8
Add polyfill for process and Buffer in webpack 5 (#15499)
timneutkens Jul 28, 2020
fef3343
improves baseUrl resolution in typescript monorepos (#13542)
jeantil Jul 28, 2020
7746263
Ignore history state not created by next.js (#15379)
Janpot Jul 28, 2020
826c52a
Fix: UnhandledPromiseRejectionWarning when unknown flag provided for …
darshkpatel Jul 28, 2020
49f2e7f
Font optimizations (#14746)
prateekbh Jul 28, 2020
10d69ea
Next.js prefetching should use requestIdleCallback (#14580)
khattakdev Jul 28, 2020
625f105
Make Links rendered in the error overlay clickable [ 14017 ] (#14055)
darshkpatel Jul 28, 2020
f9f28cd
Add release hook to format the changelog by labels (#14592)
rafaelalmeidatk Jul 28, 2020
5714d86
v9.5.1-canary.0
timneutkens Jul 28, 2020
dd5ef07
Update release.js and release package to avoid github rate limit (#15…
timneutkens Jul 28, 2020
b1fac04
Update stats-config for new polyfills location (#15584)
ijjk Jul 28, 2020
0cbfb4b
fix typo in `eslint-plugin-next` code comments (#15583)
cvan Jul 28, 2020
16d87a4
Update Electron, Typescript example (#15524)
laiso Jul 28, 2020
074c0ca
Stabilize error-is-clickable test (#15606)
ijjk Jul 29, 2020
d2e4757
Make sure link can render without router (#15604)
ijjk Jul 29, 2020
a1ca9e3
Add better typing for redirect (#15603)
rovansteen Jul 29, 2020
0b76c4b
Update multi-zone example link from relative to absolute (#15618)
yokinist Jul 29, 2020
397171c
Update header replacing to be more relaxed (#15592)
ijjk Jul 29, 2020
b16065f
Add note about statusCode config for redirects (#15615)
ijjk Jul 29, 2020
5d77988
Fix webdriver error handling (#15491)
Janpot Jul 29, 2020
e0e13fd
Normalize missing optional value on Vercel (#15593)
ijjk Jul 29, 2020
c9a3d50
Add CSS Modules examples to docs (#15601)
lfades Jul 29, 2020
faf4b9b
v9.5.1-canary.1
ijjk Jul 29, 2020
92e4ad0
Don't use assetprefix on getServerSideProps and getStaticProps (#15634)
Janpot Jul 29, 2020
9afdb43
v9.5.1-canary.2
Timer Jul 29, 2020
1766890
retry installs on macos (#15641)
Janpot Jul 29, 2020
276e72d
Remove console log from release script (#15652)
rafaelalmeidatk Jul 29, 2020
911572e
Test webpack 5 beta (#15645)
Timer Jul 29, 2020
ddbfc46
Fix: space issue in error overlay and add tests (#15617)
darshkpatel Jul 29, 2020
925bffc
remove broken server example (#15653)
Jul 29, 2020
dd9a6f7
Fix error overlay hotlinking (#15658)
Timer Jul 30, 2020
44968ad
Added docs for Incremental Static Regeneration (#15663)
lfades Jul 30, 2020
cb26265
v9.5.1-canary.3
Timer Jul 30, 2020
2790e9d
v9.5.1
Timer Jul 30, 2020
e924329
Fix hot reloader edge case with broken webpack plugins (#15659)
Timer Jul 30, 2020
47661ad
v9.5.2-canary.0
Timer Jul 30, 2020
85038cf
Add additional pageProps check (#15667)
ijjk Jul 30, 2020
1b4cdd7
Error overlay should not be dismissable for a server error (#14011)
khattakdev Jul 30, 2020
15f29e8
Strictly type `react-dev-overlay` (#15669)
Timer Jul 30, 2020
d1d0b31
Pass RouterEventMap to mitt
LauraBeatris Jul 30, 2020
b74a110
Export event emitter types
LauraBeatris Jul 30, 2020
2e44197
Fix type of spreaded events to emit event handler
LauraBeatris Jul 30, 2020
fba6400
[Examples] Fix with-sentry (#15694)
lfades Jul 30, 2020
6ac4627
[Docs] Use `next dev` for the getting started page (#15705)
lfades Jul 30, 2020
2c5b9c5
Docs smart-cdn link is dead. (#15707)
matamatanot Jul 30, 2020
05cc0a8
Document regex support for custom routes (#15714)
ijjk Jul 30, 2020
614c576
Stabilize another test (#15697)
Janpot Jul 31, 2020
1936bfb
[Docs] Add upgrade notes for Next.js 9.5 (#15703)
lfades Jul 31, 2020
37bfc65
Fix wrong asPath on 404 (#15728)
Janpot Jul 31, 2020
0fe20fa
Update next-transpile-modules in with-react-intl example (#15730)
jonespen Jul 31, 2020
e4fce03
[webpack5] Complile for ES5 (#15708)
RafalFilipek Jul 31, 2020
0cb7691
Update next-transpile-modules in all examples (#15739)
martpie Jul 31, 2020
3e455ca
Fix gh-pages deploy script (#15724)
ronaldstevanus Jul 31, 2020
c31f513
Remove unused error (#15748)
Janpot Jul 31, 2020
d80f019
v9.5.2-canary.1
Timer Jul 31, 2020
1c6a699
Fix asPath of rewrite without basePath (#15760)
Janpot Aug 1, 2020
d7caf50
Add clarification of routing to a dynamic route (#15771)
samrobbins85 Aug 1, 2020
67fdbb0
Improve router types (#15775)
Janpot Aug 1, 2020
8e1bdaa
examples: Update with-electron .gitignore (#15783)
DavidLemayian Aug 2, 2020
86b92e7
Remove dotenv from auth0 Next.js example (#15398)
msreekm Aug 2, 2020
7a93a38
Fix dotenv loading with cascading values (#15799)
ijjk Aug 2, 2020
6882447
v9.5.2-canary.2
Timer Aug 3, 2020
f4ae0c4
Remove implicitly any type
LauraBeatris Jul 30, 2020
e0fde40
Use keys of RouterHandlersMap to map router events
LauraBeatris Jul 30, 2020
bd27638
Add EventType type to router events
LauraBeatris Sep 1, 2020
acf0f77
Refactor mitt to map event handler types
LauraBeatris Sep 1, 2020
da435b6
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 1, 2020
ce7785a
Remove duplicate type
LauraBeatris Sep 1, 2020
336e720
Fix mitt import and types
LauraBeatris Sep 1, 2020
d758284
Pass any as a generic for Emitter on ServerRouter events
LauraBeatris Sep 2, 2020
a9b14b5
Pass any as a generic for Emitter on page-loader events
LauraBeatris Sep 2, 2020
0536b96
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 2, 2020
d71b882
Initialize next-server events with mitt
LauraBeatris Sep 2, 2020
eeabba3
Merge branch 'add-route-events-types' of https://github.com/LauraBeat…
LauraBeatris Sep 2, 2020
62c44f4
Pass events directly to emit handler
LauraBeatris Sep 2, 2020
172b566
Verify if event exists on mitt event
LauraBeatris Sep 2, 2020
f5ae8f2
Merge branch 'canary' into add-route-events-types
lfades Sep 2, 2020
b27c8fb
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 3, 2020
00cb0e9
Rollback changes made to the mitt logic
LauraBeatris Sep 3, 2020
8dd3832
Rollback changes made to router
LauraBeatris Sep 3, 2020
58bd572
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 3, 2020
c7fe27f
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 3, 2020
27e5c3e
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 7, 2020
647c8f1
Merge branch 'canary' into add-route-events-types
lfades Sep 16, 2020
a43b2ac
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 20, 2020
52b4c71
Add unit test for mitt module on typescript integration tests folder
LauraBeatris Sep 20, 2020
1f362c6
Add page to test the events emitter on TS integrations folder
LauraBeatris Sep 20, 2020
1c49b4b
Removed unused test
LauraBeatris Sep 20, 2020
1c3e920
Improve error type for routeChangeError event
LauraBeatris Sep 20, 2020
bdf2220
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 20, 2020
4217002
Remove unnecessary test
LauraBeatris Sep 21, 2020
1cc71c3
Merge branch 'add-route-events-types' of https://github.com/LauraBeat…
LauraBeatris Sep 21, 2020
af88d8b
Merge branch 'canary' into add-route-events-types
LauraBeatris Sep 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions packages/next/client/page-loader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ComponentType } from 'react'
import type { ClientSsgManifest } from '../build'
import type { ClientBuildManifest } from '../build/webpack/plugins/build-manifest-plugin'
import mitt from '../next-server/lib/mitt'
import type { MittEmitter } from '../next-server/lib/mitt'
import mitt, { Emitter } from '../next-server/lib/mitt'
import {
addBasePath,
markLoadingError,
Expand Down Expand Up @@ -116,7 +115,7 @@ export default class PageLoader {
private buildId: string
private assetPrefix: string
private pageCache: Record<string, PageCacheEntry>
private pageRegisterEvents: MittEmitter
private pageRegisterEvents: Emitter<any, any>
private loadingRoutes: Record<string, boolean>
private promisedBuildManifest?: Promise<ClientBuildManifest>
private promisedSsgManifest?: Promise<ClientSsgManifest>
Expand All @@ -129,7 +128,7 @@ export default class PageLoader {
this.assetPrefix = assetPrefix

this.pageCache = {}
this.pageRegisterEvents = mitt()
this.pageRegisterEvents = mitt<any, any>()
this.loadingRoutes = {
// By default these 2 pages are being loaded in the initial html
'/_app': true,
Expand Down
9 changes: 6 additions & 3 deletions packages/next/client/router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* global window */
import React from 'react'
import Router, { NextRouter } from '../next-server/lib/router/router'
import Router, {
NextRouter,
RouterEventMap,
} from '../next-server/lib/router/router'
import { RouterContext } from '../next-server/lib/router-context'

type ClassArguments<T> = T extends new (...args: infer U) => any ? U : any
Expand Down Expand Up @@ -38,7 +41,7 @@ const urlPropertyFields = [
'isFallback',
'basePath',
]
const routerEvents = [
const routerEvents: Array<keyof RouterEventMap> = [
'routeChangeStart',
'beforeHistoryChange',
'routeChangeComplete',
Expand Down Expand Up @@ -85,7 +88,7 @@ coreMethodFields.forEach((field) => {

routerEvents.forEach((event) => {
singletonRouter.ready(() => {
Router.events.on(event, (...args) => {
Router.events.on(event, (...args: any[]) => {
const eventField = `on${event.charAt(0).toUpperCase()}${event.substring(
1
)}`
Expand Down
56 changes: 38 additions & 18 deletions packages/next/next-server/lib/mitt.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,64 @@
/*
MIT License

Copyright (c) Jason Miller (https://jasonformat.com/)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// This file is based on https://github.com/developit/mitt/blob/v1.1.3/src/index.js
// It's been edited for the needs of this script
// See the LICENSE at the top of the file

type Handler = (...evts: any[]) => void
export type EventType =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this still looks incorrect. The lib/mitt file should not know about the implementation details of the Next.js router.

| 'routeChangeStart'
| 'beforeHistoryChange'
| 'routeChangeComplete'
| 'routeChangeError'
| 'hashChangeStart'
| 'hashChangeComplete'

export type Listeners = {
[K in keyof EventMap]?: Array<(p: EventMap[K]) => void>
}

export type ArgumentTypes<F extends Function> = F extends (
...args: infer A
) => any
? A
: never

export type EventMap = Record<string, any>
export type EventHandlersMap = Record<string, any>
export type EventKey<T extends EventMap> = string & keyof T

export type MittEmitter = {
on(type: string, handler: Handler): void
off(type: string, handler: Handler): void
emit(type: string, ...evts: any[]): void
export interface Emitter<T extends EventMap, H extends EventHandlersMap> {
on<K extends EventKey<T>>(eventName: K, fn: H[K]): void
off<K extends EventKey<T>>(eventName: K, fn: H[K]): void
emit<K extends EventKey<T>>(
eventName: K,
...params: ArgumentTypes<H[K]>
): void
}

export default function mitt(): MittEmitter {
const all: { [s: string]: Handler[] } = Object.create(null)
export default function mitt<
T extends EventMap,
H extends EventHandlersMap
>(): Emitter<T, H> {
const all: Listeners = Object.create(null)

return {
on(type: string, handler: Handler) {
on(type, handler) {
;(all[type] || (all[type] = [])).push(handler)
},

off(type: string, handler: Handler) {
off(type, handler) {
if (all[type]) {
all[type].splice(all[type].indexOf(handler) >>> 0, 1)
all[type]?.splice((all[type] || []).indexOf(handler) >>> 0, 1)
}
},

emit(type: string, ...evts: any[]) {
emit(type, ...evts) {
// eslint-disable-next-line array-callback-return
;(all[type] || []).slice().map((handler: Handler) => {
;(all[type] || []).slice().map((handler: any) => {
handler(...evts)
})
},
Expand Down
31 changes: 28 additions & 3 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import { ParsedUrlQuery } from 'querystring'
import { ComponentType } from 'react'
import { UrlObject } from 'url'
import mitt, { Emitter } from '../mitt'
import {
normalizePathTrailingSlash,
removePathTrailingSlash,
} from '../../../client/normalize-trailing-slash'
import { GoodPageCache, StyleSheetTuple } from '../../../client/page-loader'
import { denormalizePagePath } from '../../server/denormalize-page-path'
import mitt, { MittEmitter } from '../mitt'
import {
AppContextType,
formatWithValidation,
Expand Down Expand Up @@ -39,6 +39,16 @@ interface NextHistoryState {

type HistoryState = null | { __N: false } | ({ __N: true } & NextHistoryState)

interface TransitionOptions {
shallow?: boolean
}

interface NextHistoryState {
url: string
as: string
options: TransitionOptions
}

const basePath = (process.env.__NEXT_ROUTER_BASEPATH as string) || ''

function buildCancellationError() {
Expand Down Expand Up @@ -237,6 +247,21 @@ export type NextRouter = BaseRouter &
| 'isFallback'
>

export type RouterEventError = {
[key: string]: any
cancelled: boolean
}

export type RouterHandlersMap = {
routeChangeStart: (url: string) => void
beforeHistoryChange: (url: string) => void
routeChangeComplete: (url: string) => void
routeChangeError: (err: RouterEventError, url: string) => void
hashChangeStart: (url: string) => void
hashChangeComplete: (url: string) => void
}
export type RouterEventMap = Record<keyof RouterHandlersMap, any>

export type PrefetchOptions = {
priority?: boolean
}
Expand Down Expand Up @@ -324,14 +349,14 @@ export default class Router implements BaseRouter {
clc: ComponentLoadCancel
pageLoader: any
_bps: BeforePopStateCallback | undefined
events: MittEmitter
events: Emitter<RouterEventMap, RouterHandlersMap>
_wrapApp: (App: AppComponent) => any
isSsr: boolean
isFallback: boolean
_inFlightRoute?: string
_shallow?: boolean

static events: MittEmitter = mitt()
static events = mitt<RouterEventMap, RouterHandlersMap>()

constructor(
pathname: string,
Expand Down
4 changes: 2 additions & 2 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { defaultHead } from '../lib/head'
import { HeadManagerContext } from '../lib/head-manager-context'
import Loadable from '../lib/loadable'
import { LoadableContext } from '../lib/loadable-context'
import mitt, { MittEmitter } from '../lib/mitt'
import mitt, { Emitter } from '../lib/mitt'
import postProcess from '../lib/post-process'
import { RouterContext } from '../lib/router-context'
import { NextRouter } from '../lib/router/router'
Expand Down Expand Up @@ -68,7 +68,7 @@ class ServerRouter implements NextRouter {
events: any
isFallback: boolean
// TODO: Remove in the next major version, as this would mean the user is adding event listeners in server-side `render` method
static events: MittEmitter = mitt()
static events: Emitter<any, any> = mitt()

constructor(
pathname: string,
Expand Down
33 changes: 33 additions & 0 deletions test/integration/typescript/pages/routerEvents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect, useState } from 'react'
import Router from 'next/router'

const RouterEvents: React.FC = () => {
const [routerEvent, setRouterEvent] = useState('')
const [routerEventError, setRouterEventError] = useState('')

useEffect(() => {
Router.events.on('routeChangeStart', () =>
setRouterEvent('routeChangeStart')
)

Router.events.on('routeChangeComplete', () =>
setRouterEvent('routeChangeComplete')
)

Router.events.on('routeChangeError', (error) => {
setRouterEvent('routeChangeError')

setRouterEventError(error.message)
})
LauraBeatris marked this conversation as resolved.
Show resolved Hide resolved
}, [])

return (
<div>
{routerEvent && <p>{routerEvent}</p>}

{routerEventError && <p>{routerEventError}</p>}
</div>
)
}

export default RouterEvents