From cf87882130e991fa4f26782a462c503faf8e5f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Mon, 20 Jun 2022 15:04:06 +0900 Subject: [PATCH] refactor: type client maps (#8626) --- docs/guide/api-hmr.md | 20 +++++++++++++++----- packages/vite/src/client/client.ts | 26 +++++++++++++++----------- packages/vite/types/hot.d.ts | 13 ++++++++++--- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/docs/guide/api-hmr.md b/docs/guide/api-hmr.md index 1cba492e6613c1..3b416169f5231a 100644 --- a/docs/guide/api-hmr.md +++ b/docs/guide/api-hmr.md @@ -13,13 +13,20 @@ interface ImportMeta { readonly hot?: ViteHotContext } +type ModuleNamespace = Record & { + [Symbol.toStringTag]: 'Module' +} + interface ViteHotContext { readonly data: any accept(): void - accept(cb: (mod: any) => void): void - accept(dep: string, cb: (mod: any) => void): void - accept(deps: readonly string[], cb: (mods: any[]) => void): void + accept(cb: (mod: ModuleNamespace | undefined) => void): void + accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void + accept( + deps: readonly string[], + cb: (mods: Array) => void + ): void dispose(cb: (data: any) => void): void decline(): void @@ -53,7 +60,10 @@ export const count = 1 if (import.meta.hot) { import.meta.hot.accept((newModule) => { - console.log('updated: count is now ', newModule.count) + if (newModule) { + // newModule is undefined when SyntaxError happened + console.log('updated: count is now ', newModule.count) + } }) } ``` @@ -76,7 +86,7 @@ foo() if (import.meta.hot) { import.meta.hot.accept('./foo.js', (newFoo) => { // the callback receives the updated './foo.js' module - newFoo.foo() + newFoo?.foo() }) // Can also accept an array of dep modules: diff --git a/packages/vite/src/client/client.ts b/packages/vite/src/client/client.ts index 8f39164e05a774..6762786218fc42 100644 --- a/packages/vite/src/client/client.ts +++ b/packages/vite/src/client/client.ts @@ -1,5 +1,5 @@ import type { ErrorPayload, HMRPayload, Update } from 'types/hmrPayload' -import type { ViteHotContext } from 'types/hot' +import type { ModuleNamespace, ViteHotContext } from 'types/hot' import type { InferCustomEventPayload } from 'types/customEvent' import { ErrorOverlay, overlayId } from './overlay' // eslint-disable-next-line node/no-missing-import @@ -248,7 +248,10 @@ const supportsConstructedSheet = (() => { return false })() -const sheetsMap = new Map() +const sheetsMap = new Map< + string, + HTMLStyleElement | CSSStyleSheet | undefined +>() export function updateStyle(id: string, content: string): void { let style = sheetsMap.get(id) @@ -260,10 +263,12 @@ export function updateStyle(id: string, content: string): void { if (!style) { style = new CSSStyleSheet() + // @ts-expect-error: using experimental API style.replaceSync(content) // @ts-expect-error: using experimental API document.adoptedStyleSheets = [...document.adoptedStyleSheets, style] } else { + // @ts-expect-error: using experimental API style.replaceSync(content) } } else { @@ -308,7 +313,7 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) { return } - const moduleMap = new Map() + const moduleMap = new Map() const isSelfUpdate = path === acceptedPath // make sure we only import each dep once @@ -338,7 +343,7 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) { if (disposer) await disposer(dataMap.get(dep)) const [path, query] = dep.split(`?`) try { - const newMod = await import( + const newMod: ModuleNamespace = await import( /* @vite-ignore */ base + path.slice(1) + @@ -375,18 +380,17 @@ interface HotModule { interface HotCallback { // the dependencies must be fetchable paths deps: string[] - fn: (modules: object[]) => void + fn: (modules: Array) => void } +type CustomListenersMap = Map void)[]> + const hotModulesMap = new Map() const disposeMap = new Map void | Promise>() const pruneMap = new Map void | Promise>() const dataMap = new Map() -const customListenersMap = new Map void)[]>() -const ctxToListenersMap = new Map< - string, - Map void)[]> ->() +const customListenersMap: CustomListenersMap = new Map() +const ctxToListenersMap = new Map() export function createHotContext(ownerPath: string): ViteHotContext { if (!dataMap.has(ownerPath)) { @@ -414,7 +418,7 @@ export function createHotContext(ownerPath: string): ViteHotContext { } } - const newListeners = new Map() + const newListeners: CustomListenersMap = new Map() ctxToListenersMap.set(ownerPath, newListeners) function acceptDeps(deps: string[], callback: HotCallback['fn'] = () => {}) { diff --git a/packages/vite/types/hot.d.ts b/packages/vite/types/hot.d.ts index daaf44e1efdc74..33299ec0f36354 100644 --- a/packages/vite/types/hot.d.ts +++ b/packages/vite/types/hot.d.ts @@ -1,12 +1,19 @@ import type { InferCustomEventPayload } from './customEvent' +export type ModuleNamespace = Record & { + [Symbol.toStringTag]: 'Module' +} + export interface ViteHotContext { readonly data: any accept(): void - accept(cb: (mod: any) => void): void - accept(dep: string, cb: (mod: any) => void): void - accept(deps: readonly string[], cb: (mods: any[]) => void): void + accept(cb: (mod: ModuleNamespace | undefined) => void): void + accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void + accept( + deps: readonly string[], + cb: (mods: Array) => void + ): void dispose(cb: (data: any) => void): void decline(): void invalidate(): void