mirror of https://github.com/vuejs/core.git
175 lines
4.8 KiB
TypeScript
175 lines
4.8 KiB
TypeScript
/* eslint-disable no-restricted-globals */
|
|
import type { App } from './apiCreateApp'
|
|
import { Comment, Fragment, Static, Text } from './vnode'
|
|
import type { ComponentInternalInstance } from './component'
|
|
|
|
interface AppRecord {
|
|
id: number
|
|
app: App
|
|
version: string
|
|
types: Record<string, string | Symbol>
|
|
}
|
|
|
|
enum DevtoolsHooks {
|
|
APP_INIT = 'app:init',
|
|
APP_UNMOUNT = 'app:unmount',
|
|
COMPONENT_UPDATED = 'component:updated',
|
|
COMPONENT_ADDED = 'component:added',
|
|
COMPONENT_REMOVED = 'component:removed',
|
|
COMPONENT_EMIT = 'component:emit',
|
|
PERFORMANCE_START = 'perf:start',
|
|
PERFORMANCE_END = 'perf:end',
|
|
}
|
|
|
|
export interface DevtoolsHook {
|
|
enabled?: boolean
|
|
emit: (event: string, ...payload: any[]) => void
|
|
on: (event: string, handler: Function) => void
|
|
once: (event: string, handler: Function) => void
|
|
off: (event: string, handler: Function) => void
|
|
appRecords: AppRecord[]
|
|
/**
|
|
* Added at https://github.com/vuejs/devtools/commit/f2ad51eea789006ab66942e5a27c0f0986a257f9
|
|
* Returns whether the arg was buffered or not
|
|
*/
|
|
cleanupBuffer?: (matchArg: unknown) => boolean
|
|
}
|
|
|
|
export let devtools: DevtoolsHook
|
|
|
|
let buffer: { event: string; args: any[] }[] = []
|
|
|
|
let devtoolsNotInstalled = false
|
|
|
|
function emit(event: string, ...args: any[]) {
|
|
if (devtools) {
|
|
devtools.emit(event, ...args)
|
|
} else if (!devtoolsNotInstalled) {
|
|
buffer.push({ event, args })
|
|
}
|
|
}
|
|
|
|
export function setDevtoolsHook(hook: DevtoolsHook, target: any): void {
|
|
devtools = hook
|
|
if (devtools) {
|
|
devtools.enabled = true
|
|
buffer.forEach(({ event, args }) => devtools.emit(event, ...args))
|
|
buffer = []
|
|
} else if (
|
|
// handle late devtools injection - only do this if we are in an actual
|
|
// browser environment to avoid the timer handle stalling test runner exit
|
|
// (#4815)
|
|
typeof window !== 'undefined' &&
|
|
// some envs mock window but not fully
|
|
window.HTMLElement &&
|
|
// also exclude jsdom
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
!window.navigator?.userAgent?.includes('jsdom')
|
|
) {
|
|
const replay = (target.__VUE_DEVTOOLS_HOOK_REPLAY__ =
|
|
target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [])
|
|
replay.push((newHook: DevtoolsHook) => {
|
|
setDevtoolsHook(newHook, target)
|
|
})
|
|
// clear buffer after 3s - the user probably doesn't have devtools installed
|
|
// at all, and keeping the buffer will cause memory leaks (#4738)
|
|
setTimeout(() => {
|
|
if (!devtools) {
|
|
target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null
|
|
devtoolsNotInstalled = true
|
|
buffer = []
|
|
}
|
|
}, 3000)
|
|
} else {
|
|
// non-browser env, assume not installed
|
|
devtoolsNotInstalled = true
|
|
buffer = []
|
|
}
|
|
}
|
|
|
|
export function devtoolsInitApp(app: App, version: string): void {
|
|
emit(DevtoolsHooks.APP_INIT, app, version, {
|
|
Fragment,
|
|
Text,
|
|
Comment,
|
|
Static,
|
|
})
|
|
}
|
|
|
|
export function devtoolsUnmountApp(app: App): void {
|
|
emit(DevtoolsHooks.APP_UNMOUNT, app)
|
|
}
|
|
|
|
export const devtoolsComponentAdded: DevtoolsComponentHook =
|
|
/*@__PURE__*/ createDevtoolsComponentHook(DevtoolsHooks.COMPONENT_ADDED)
|
|
|
|
export const devtoolsComponentUpdated: DevtoolsComponentHook =
|
|
/*@__PURE__*/ createDevtoolsComponentHook(DevtoolsHooks.COMPONENT_UPDATED)
|
|
|
|
const _devtoolsComponentRemoved = /*@__PURE__*/ createDevtoolsComponentHook(
|
|
DevtoolsHooks.COMPONENT_REMOVED,
|
|
)
|
|
|
|
export const devtoolsComponentRemoved = (
|
|
component: ComponentInternalInstance,
|
|
): void => {
|
|
if (
|
|
devtools &&
|
|
typeof devtools.cleanupBuffer === 'function' &&
|
|
// remove the component if it wasn't buffered
|
|
!devtools.cleanupBuffer(component)
|
|
) {
|
|
_devtoolsComponentRemoved(component)
|
|
}
|
|
}
|
|
|
|
type DevtoolsComponentHook = (component: ComponentInternalInstance) => void
|
|
|
|
/*! #__NO_SIDE_EFFECTS__ */
|
|
function createDevtoolsComponentHook(
|
|
hook: DevtoolsHooks,
|
|
): DevtoolsComponentHook {
|
|
return (component: ComponentInternalInstance) => {
|
|
emit(
|
|
hook,
|
|
component.appContext.app,
|
|
component.uid,
|
|
component.parent ? component.parent.uid : undefined,
|
|
component,
|
|
)
|
|
}
|
|
}
|
|
|
|
export const devtoolsPerfStart: DevtoolsPerformanceHook =
|
|
/*@__PURE__*/ createDevtoolsPerformanceHook(DevtoolsHooks.PERFORMANCE_START)
|
|
|
|
export const devtoolsPerfEnd: DevtoolsPerformanceHook =
|
|
/*@__PURE__*/ createDevtoolsPerformanceHook(DevtoolsHooks.PERFORMANCE_END)
|
|
|
|
type DevtoolsPerformanceHook = (
|
|
component: ComponentInternalInstance,
|
|
type: string,
|
|
time: number,
|
|
) => void
|
|
function createDevtoolsPerformanceHook(
|
|
hook: DevtoolsHooks,
|
|
): DevtoolsPerformanceHook {
|
|
return (component: ComponentInternalInstance, type: string, time: number) => {
|
|
emit(hook, component.appContext.app, component.uid, component, type, time)
|
|
}
|
|
}
|
|
|
|
export function devtoolsComponentEmit(
|
|
component: ComponentInternalInstance,
|
|
event: string,
|
|
params: any[],
|
|
): void {
|
|
emit(
|
|
DevtoolsHooks.COMPONENT_EMIT,
|
|
component.appContext.app,
|
|
component,
|
|
event,
|
|
params,
|
|
)
|
|
}
|