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

refactor: type client maps #8626

Merged
merged 3 commits into from Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 15 additions & 5 deletions docs/guide/api-hmr.md
Expand Up @@ -13,13 +13,20 @@ interface ImportMeta {
readonly hot?: ViteHotContext
}

type ModuleNamespace = Record<string, any> & {
[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<ModuleNamespace | undefined>) => void
): void

dispose(cb: (data: any) => void): void
decline(): void
Expand Down Expand Up @@ -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)
}
})
}
```
Expand All @@ -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:
Expand Down
26 changes: 15 additions & 11 deletions 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
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand Down Expand Up @@ -308,7 +313,7 @@ async function fetchUpdate({ path, acceptedPath, timestamp }: Update) {
return
}

const moduleMap = new Map()
const moduleMap = new Map<string, ModuleNamespace>()
const isSelfUpdate = path === acceptedPath

// make sure we only import each dep once
Expand Down Expand Up @@ -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) +
Expand Down Expand Up @@ -375,18 +380,17 @@ interface HotModule {
interface HotCallback {
// the dependencies must be fetchable paths
deps: string[]
fn: (modules: object[]) => void
fn: (modules: Array<ModuleNamespace | undefined>) => void
}

type CustomListenersMap = Map<string, ((data: any) => void)[]>

const hotModulesMap = new Map<string, HotModule>()
const disposeMap = new Map<string, (data: any) => void | Promise<void>>()
const pruneMap = new Map<string, (data: any) => void | Promise<void>>()
const dataMap = new Map<string, any>()
const customListenersMap = new Map<string, ((data: any) => void)[]>()
const ctxToListenersMap = new Map<
string,
Map<string, ((data: any) => void)[]>
>()
const customListenersMap: CustomListenersMap = new Map()
const ctxToListenersMap = new Map<string, CustomListenersMap>()

export function createHotContext(ownerPath: string): ViteHotContext {
if (!dataMap.has(ownerPath)) {
Expand Down Expand Up @@ -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'] = () => {}) {
Expand Down
13 changes: 10 additions & 3 deletions packages/vite/types/hot.d.ts
@@ -1,12 +1,19 @@
import type { InferCustomEventPayload } from './customEvent'

export type ModuleNamespace = Record<string, any> & {
[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<ModuleNamespace | undefined>) => void
): void
dispose(cb: (data: any) => void): void
decline(): void
invalidate(): void
Expand Down