Skip to content

Commit cf87882

Browse files
authored
refactor: type client maps (#8626)
1 parent eb52d36 commit cf87882

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

docs/guide/api-hmr.md

+15-5
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ interface ImportMeta {
1313
readonly hot?: ViteHotContext
1414
}
1515

16+
type ModuleNamespace = Record<string, any> & {
17+
[Symbol.toStringTag]: 'Module'
18+
}
19+
1620
interface ViteHotContext {
1721
readonly data: any
1822

1923
accept(): void
20-
accept(cb: (mod: any) => void): void
21-
accept(dep: string, cb: (mod: any) => void): void
22-
accept(deps: readonly string[], cb: (mods: any[]) => void): void
24+
accept(cb: (mod: ModuleNamespace | undefined) => void): void
25+
accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void
26+
accept(
27+
deps: readonly string[],
28+
cb: (mods: Array<ModuleNamespace | undefined>) => void
29+
): void
2330

2431
dispose(cb: (data: any) => void): void
2532
decline(): void
@@ -53,7 +60,10 @@ export const count = 1
5360

5461
if (import.meta.hot) {
5562
import.meta.hot.accept((newModule) => {
56-
console.log('updated: count is now ', newModule.count)
63+
if (newModule) {
64+
// newModule is undefined when SyntaxError happened
65+
console.log('updated: count is now ', newModule.count)
66+
}
5767
})
5868
}
5969
```
@@ -76,7 +86,7 @@ foo()
7686
if (import.meta.hot) {
7787
import.meta.hot.accept('./foo.js', (newFoo) => {
7888
// the callback receives the updated './foo.js' module
79-
newFoo.foo()
89+
newFoo?.foo()
8090
})
8191

8292
// Can also accept an array of dep modules:

packages/vite/src/client/client.ts

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ErrorPayload, HMRPayload, Update } from 'types/hmrPayload'
2-
import type { ViteHotContext } from 'types/hot'
2+
import type { ModuleNamespace, ViteHotContext } from 'types/hot'
33
import type { InferCustomEventPayload } from 'types/customEvent'
44
import { ErrorOverlay, overlayId } from './overlay'
55
// eslint-disable-next-line node/no-missing-import
@@ -248,7 +248,10 @@ const supportsConstructedSheet = (() => {
248248
return false
249249
})()
250250

251-
const sheetsMap = new Map()
251+
const sheetsMap = new Map<
252+
string,
253+
HTMLStyleElement | CSSStyleSheet | undefined
254+
>()
252255

253256
export function updateStyle(id: string, content: string): void {
254257
let style = sheetsMap.get(id)
@@ -260,10 +263,12 @@ export function updateStyle(id: string, content: string): void {
260263

261264
if (!style) {
262265
style = new CSSStyleSheet()
266+
// @ts-expect-error: using experimental API
263267
style.replaceSync(content)
264268
// @ts-expect-error: using experimental API
265269
document.adoptedStyleSheets = [...document.adoptedStyleSheets, style]
266270
} else {
271+
// @ts-expect-error: using experimental API
267272
style.replaceSync(content)
268273
}
269274
} else {
@@ -308,7 +313,7 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
308313
return
309314
}
310315

311-
const moduleMap = new Map()
316+
const moduleMap = new Map<string, ModuleNamespace>()
312317
const isSelfUpdate = path === acceptedPath
313318

314319
// make sure we only import each dep once
@@ -338,7 +343,7 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
338343
if (disposer) await disposer(dataMap.get(dep))
339344
const [path, query] = dep.split(`?`)
340345
try {
341-
const newMod = await import(
346+
const newMod: ModuleNamespace = await import(
342347
/* @vite-ignore */
343348
base +
344349
path.slice(1) +
@@ -375,18 +380,17 @@ interface HotModule {
375380
interface HotCallback {
376381
// the dependencies must be fetchable paths
377382
deps: string[]
378-
fn: (modules: object[]) => void
383+
fn: (modules: Array<ModuleNamespace | undefined>) => void
379384
}
380385

386+
type CustomListenersMap = Map<string, ((data: any) => void)[]>
387+
381388
const hotModulesMap = new Map<string, HotModule>()
382389
const disposeMap = new Map<string, (data: any) => void | Promise<void>>()
383390
const pruneMap = new Map<string, (data: any) => void | Promise<void>>()
384391
const dataMap = new Map<string, any>()
385-
const customListenersMap = new Map<string, ((data: any) => void)[]>()
386-
const ctxToListenersMap = new Map<
387-
string,
388-
Map<string, ((data: any) => void)[]>
389-
>()
392+
const customListenersMap: CustomListenersMap = new Map()
393+
const ctxToListenersMap = new Map<string, CustomListenersMap>()
390394

391395
export function createHotContext(ownerPath: string): ViteHotContext {
392396
if (!dataMap.has(ownerPath)) {
@@ -414,7 +418,7 @@ export function createHotContext(ownerPath: string): ViteHotContext {
414418
}
415419
}
416420

417-
const newListeners = new Map()
421+
const newListeners: CustomListenersMap = new Map()
418422
ctxToListenersMap.set(ownerPath, newListeners)
419423

420424
function acceptDeps(deps: string[], callback: HotCallback['fn'] = () => {}) {

packages/vite/types/hot.d.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import type { InferCustomEventPayload } from './customEvent'
22

3+
export type ModuleNamespace = Record<string, any> & {
4+
[Symbol.toStringTag]: 'Module'
5+
}
6+
37
export interface ViteHotContext {
48
readonly data: any
59

610
accept(): void
7-
accept(cb: (mod: any) => void): void
8-
accept(dep: string, cb: (mod: any) => void): void
9-
accept(deps: readonly string[], cb: (mods: any[]) => void): void
11+
accept(cb: (mod: ModuleNamespace | undefined) => void): void
12+
accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void
13+
accept(
14+
deps: readonly string[],
15+
cb: (mods: Array<ModuleNamespace | undefined>) => void
16+
): void
1017
dispose(cb: (data: any) => void): void
1118
decline(): void
1219
invalidate(): void

0 commit comments

Comments
 (0)